Merge pull request #4696 from colemanw/CRM-15669
[civicrm-core.git] / CRM / Activity / Import / Parser / Activity.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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-2014
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 public 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 */
70 public function init() {
71 $activityContact = CRM_Activity_BAO_ActivityContact::import();
72 $activityTarget['target_contact_id'] = $activityContact['contact_id'];
73 $fields = array_merge(CRM_Activity_BAO_Activity::importableFields(),
74 $activityTarget
75 );
76
77 $fields = array_merge($fields, array(
78 'source_contact_id' => array(
79 'title' => ts('Source Contact'),
80 'headerPattern' => '/Source.Contact?/i',
81 ),
82 'activity_label' => array(
83 'title' => ts('Activity Type Label'),
84 'headerPattern' => '/(activity.)?type label?/i',
85 )
86 ));
87
88 foreach ($fields as $name => $field) {
89 $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT);
90 $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//');
91 $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//');
92 $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']);
93 }
94
95 $this->_newActivity = array();
96
97 $this->setActiveFields($this->_mapperKeys);
98
99 // FIXME: we should do this in one place together with Form/MapField.php
100 $this->_contactIdIndex = -1;
101 $this->_activityTypeIndex = -1;
102 $this->_activityLabelIndex = -1;
103 $this->_activityDateIndex = -1;
104
105 $index = 0;
106 foreach ($this->_mapperKeys as $key) {
107 switch ($key) {
108 case 'target_contact_id':
109 case 'external_identifier':
110 $this->_contactIdIndex = $index;
111 break;
112
113 case 'activity_label':
114 $this->_activityLabelIndex = $index;
115 break;
116
117 case 'activity_type_id':
118 $this->_activityTypeIndex = $index;
119 break;
120
121 case 'activity_date_time':
122 $this->_activityDateIndex = $index;
123 break;
124 }
125 $index++;
126 }
127 }
128
129 /**
130 * Handle the values in mapField mode
131 *
132 * @param array $values the array of values belonging to this line
133 *
134 * @return boolean
135 */
136 public function mapField(&$values) {
137 return CRM_Import_Parser::VALID;
138 }
139
140 /**
141 * Handle the values in preview mode
142 *
143 * @param array $values the array of values belonging to this line
144 *
145 * @return boolean the result of this processing
146 */
147 public function preview(&$values) {
148 return $this->summary($values);
149 }
150
151 /**
152 * Handle the values in summary mode
153 *
154 * @param array $values the array of values belonging to this line
155 *
156 * @return boolean the result of this processing
157 */
158 public function summary(&$values) {
159 $erroneousField = NULL;
160 $response = $this->setActiveFieldValues($values, $erroneousField);
161 $index = -1;
162 $errorRequired = FALSE;
163
164 if ($this->_activityTypeIndex > -1 && $this->_activityLabelIndex > -1) {
165 array_unshift($values, ts('Please select either Activity Type ID OR Activity Type Label.'));
166 return CRM_Import_Parser::ERROR;
167 }
168 elseif ($this->_activityLabelIndex > -1) {
169 $index = $this->_activityLabelIndex;
170 }
171 elseif ($this->_activityTypeIndex > -1) {
172 $index = $this->_activityTypeIndex;
173 }
174
175 if ($index < 0 or $this->_activityDateIndex < 0) {
176 $errorRequired = TRUE;
177 }
178 else {
179 $errorRequired = !CRM_Utils_Array::value($index, $values) || !CRM_Utils_Array::value($this->_activityDateIndex, $values);
180 }
181
182 if ($errorRequired) {
183 array_unshift($values, ts('Missing required fields'));
184 return CRM_Import_Parser::ERROR;
185 }
186
187 $params = &$this->getActiveFieldParams();
188
189 $errorMessage = NULL;
190
191 //for date-Formats
192 $session = CRM_Core_Session::singleton();
193 $dateType = $session->get('dateTypes');
194 if (!isset($params['source_contact_id'])) {
195 $params['source_contact_id'] = $session->get('userID');
196 }
197 foreach ($params as $key => $val) {
198 if ($key == 'activity_date_time') {
199 if ($val) {
200 $dateValue = CRM_Utils_Date::formatDate($val, $dateType);
201 if ($dateValue) {
202 $params[$key] = $dateValue;
203 }
204 else {
205 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Activity date', $errorMessage);
206 }
207 }
208 }
209 elseif ($key == 'activity_engagement_level' && $val &&
210 !CRM_Utils_Rule::positiveInteger($val)
211 ) {
212 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Activity Engagement Index', $errorMessage);
213 }
214 }
215 //date-Format part ends
216
217 //checking error in custom data
218 $params['contact_type'] = isset($this->_contactType) ? $this->_contactType : 'Activity';
219
220 CRM_Contact_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage);
221
222 if ($errorMessage) {
223 $tempMsg = "Invalid value for field(s) : $errorMessage";
224 array_unshift($values, $tempMsg);
225 $errorMessage = NULL;
226 return CRM_Import_Parser::ERROR;
227 }
228
229 return CRM_Import_Parser::VALID;
230 }
231
232 /**
233 * Handle the values in import mode
234 *
235 * @param int $onDuplicate the code for what action to take on duplicates
236 * @param array $values the array of values belonging to this line
237 *
238 * @return boolean the result of this processing
239 */
240 public function import($onDuplicate, &$values) {
241 // first make sure this is a valid line
242 $response = $this->summary($values);
243
244 if ($response != CRM_Import_Parser::VALID) {
245 return $response;
246 }
247 $params = &$this->getActiveFieldParams();
248 $activityLabel = array_search('activity_label', $this->_mapperKeys);
249 if ($activityLabel) {
250 $params = array_merge($params, array('activity_label' => $values[$activityLabel]));
251 }
252 //for date-Formats
253 $session = CRM_Core_Session::singleton();
254 $dateType = $session->get('dateTypes');
255 if (!isset($params['source_contact_id'])) {
256 $params['source_contact_id'] = $session->get('userID');
257 }
258 $formatted = array();
259 $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $params));
260
261 foreach ($params as $key => $val) {
262 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
263 if ($key == 'activity_date_time' && $val) {
264 $params[$key] = CRM_Utils_Date::formatDate($val, $dateType);
265 }
266 elseif (!empty($customFields[$customFieldID]) && $customFields[$customFieldID]['data_type'] == 'Date') {
267 CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $params, $dateType, $key);
268 }
269 elseif (!empty($customFields[$customFieldID]) && $customFields[$customFieldID]['data_type'] == 'Boolean') {
270 $params[$key] = CRM_Utils_String::strtoboolstr($val);
271 }
272 }
273 elseif ($key == 'activity_date_time') {
274 $params[$key] = CRM_Utils_Date::formatDate($val, $dateType);
275 }
276 elseif ($key == 'activity_subject') {
277 $params['subject'] = $val;
278 }
279 }
280 //date-Format part ends
281 require_once 'CRM/Utils/DeprecatedUtils.php';
282 $formatError = _civicrm_api3_deprecated_activity_formatted_param($params, $params, TRUE);
283
284 if ($formatError) {
285 array_unshift($values, $formatError['error_message']);
286 return CRM_Import_Parser::ERROR;
287 }
288
289 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
290 CRM_Core_DAO::$_nullObject,
291 NULL,
292 'Activity'
293 );
294
295 if ($this->_contactIdIndex < 0) {
296
297 //retrieve contact id using contact dedupe rule.
298 //since we are support only individual's activity import.
299 $params['contact_type'] = 'Individual';
300 $params['version'] = 3;
301 $error = _civicrm_api3_deprecated_duplicate_formatted_contact($params);
302
303 if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) {
304 $matchedIDs = explode(',', $error['error_message']['params'][0]);
305 if (count($matchedIDs) > 1) {
306 array_unshift($values, 'Multiple matching contact records detected for this row. The activity was not imported');
307 return CRM_Import_Parser::ERROR;
308 }
309 else {
310 $cid = $matchedIDs[0];
311 $params['target_contact_id'] = $cid;
312 $params['version'] = 3;
313 $newActivity = civicrm_api('activity', 'create', $params);
314 if (!empty($newActivity['is_error'])) {
315 array_unshift($values, $newActivity['error_message']);
316 return CRM_Import_Parser::ERROR;
317 }
318
319 $this->_newActivity[] = $newActivity['id'];
320 return CRM_Import_Parser::VALID;
321 }
322 }
323 else {
324 // Using new Dedupe rule.
325 $ruleParams = array(
326 'contact_type' => 'Individual',
327 'used' => 'Unsupervised',
328 );
329 $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams);
330
331 $disp = NULL;
332 foreach ($fieldsArray as $value) {
333 if (array_key_exists(trim($value), $params)) {
334 $paramValue = $params[trim($value)];
335 if (is_array($paramValue)) {
336 $disp .= $params[trim($value)][0][trim($value)] . " ";
337 }
338 else {
339 $disp .= $params[trim($value)] . " ";
340 }
341 }
342 }
343
344 if (!empty($params['external_identifier'])) {
345 if ($disp) {
346 $disp .= "AND {$params['external_identifier']}";
347 }
348 else {
349 $disp = $params['external_identifier'];
350 }
351 }
352
353 array_unshift($values, 'No matching Contact found for (' . $disp . ')');
354 return CRM_Import_Parser::ERROR;
355 }
356 }
357 else {
358 if (!empty($params['external_identifier'])) {
359 $targetContactId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
360 $params['external_identifier'], 'id', 'external_identifier'
361 );
362
363 if (!empty($params['target_contact_id']) &&
364 $params['target_contact_id'] != $targetContactId
365 ) {
366 array_unshift($values, 'Mismatch of External identifier :' . $params['external_identifier'] . ' and Contact Id:' . $params['target_contact_id']);
367 return CRM_Import_Parser::ERROR;
368 }
369 elseif ($targetContactId) {
370 $params['target_contact_id'] = $targetContactId;
371 }
372 else {
373 array_unshift($values, 'No Matching Contact for External identifier :' . $params['external_identifier']);
374 return CRM_Import_Parser::ERROR;
375 }
376 }
377
378 $params['version'] = 3;
379 $newActivity = civicrm_api('activity', 'create', $params);
380 if (!empty($newActivity['is_error'])) {
381 array_unshift($values, $newActivity['error_message']);
382 return CRM_Import_Parser::ERROR;
383 }
384
385 $this->_newActivity[] = $newActivity['id'];
386 return CRM_Import_Parser::VALID;
387 }
388 }
389
390 /**
391 * The initializer code, called before the processing
392 *
393 * @return void
394 */
395 public function fini() {}
396
397 }