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