3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
20 * Class to parse activity csv files.
22 class CRM_Activity_Import_Parser_Activity
extends CRM_Activity_Import_Parser
{
24 protected $_mapperKeys;
26 private $_contactIdIndex;
27 private $_activityTypeIndex;
28 private $_activityLabelIndex;
29 private $_activityDateIndex;
32 * Array of successfully imported activity id's
36 protected $_newActivity;
41 * @param array $mapperKeys
43 public function __construct(&$mapperKeys) {
44 parent
::__construct();
45 $this->_mapperKeys
= &$mapperKeys;
49 * Function of undocumented functionality required by the interface.
51 protected function fini() {}
54 * The initializer code, called before the processing.
56 public function init() {
57 $activityContact = CRM_Activity_BAO_ActivityContact
::import();
58 $activityTarget['target_contact_id'] = $activityContact['contact_id'];
59 $fields = array_merge(CRM_Activity_BAO_Activity
::importableFields(),
63 $fields = array_merge($fields, [
64 'source_contact_id' => [
65 'title' => ts('Source Contact'),
66 'headerPattern' => '/Source.Contact?/i',
69 'title' => ts('Activity Type Label'),
70 'headerPattern' => '/(activity.)?type label?/i',
74 foreach ($fields as $name => $field) {
75 $field['type'] = CRM_Utils_Array
::value('type', $field, CRM_Utils_Type
::T_INT
);
76 $field['dataPattern'] = CRM_Utils_Array
::value('dataPattern', $field, '//');
77 $field['headerPattern'] = CRM_Utils_Array
::value('headerPattern', $field, '//');
78 $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']);
81 $this->_newActivity
= [];
83 $this->setActiveFields($this->_mapperKeys
);
85 // FIXME: we should do this in one place together with Form/MapField.php
86 $this->_contactIdIndex
= -1;
87 $this->_activityTypeIndex
= -1;
88 $this->_activityLabelIndex
= -1;
89 $this->_activityDateIndex
= -1;
92 foreach ($this->_mapperKeys
as $key) {
94 case 'target_contact_id':
95 case 'external_identifier':
96 $this->_contactIdIndex
= $index;
99 case 'activity_label':
100 $this->_activityLabelIndex
= $index;
103 case 'activity_type_id':
104 $this->_activityTypeIndex
= $index;
107 case 'activity_date_time':
108 $this->_activityDateIndex
= $index;
116 * Handle the values in mapField mode.
118 * @param array $values
119 * The array of values belonging to this line.
123 public function mapField(&$values) {
124 return CRM_Import_Parser
::VALID
;
128 * Handle the values in preview mode.
130 * @param array $values
131 * The array of values belonging to this line.
134 * the result of this processing
136 public function preview(&$values) {
137 return $this->summary($values);
141 * Handle the values in summary mode.
143 * @param array $values
144 * The array of values belonging to this line.
147 * the result of this processing
149 public function summary(&$values) {
150 $erroneousField = NULL;
151 $this->setActiveFieldValues($values, $erroneousField);
154 if ($this->_activityTypeIndex
> -1 && $this->_activityLabelIndex
> -1) {
155 array_unshift($values, ts('Please select either Activity Type ID OR Activity Type Label.'));
156 return CRM_Import_Parser
::ERROR
;
158 elseif ($this->_activityLabelIndex
> -1) {
159 $index = $this->_activityLabelIndex
;
161 elseif ($this->_activityTypeIndex
> -1) {
162 $index = $this->_activityTypeIndex
;
165 if ($index < 0 or $this->_activityDateIndex
< 0) {
166 $errorRequired = TRUE;
169 $errorRequired = !CRM_Utils_Array
::value($index, $values) ||
!CRM_Utils_Array
::value($this->_activityDateIndex
, $values);
172 if ($errorRequired) {
173 array_unshift($values, ts('Missing required fields'));
174 return CRM_Import_Parser
::ERROR
;
177 $params = &$this->getActiveFieldParams();
179 $errorMessage = NULL;
182 $session = CRM_Core_Session
::singleton();
183 $dateType = $session->get('dateTypes');
184 if (!isset($params['source_contact_id'])) {
185 $params['source_contact_id'] = $session->get('userID');
187 foreach ($params as $key => $val) {
188 if ($key == 'activity_date_time') {
190 $dateValue = CRM_Utils_Date
::formatDate($val, $dateType);
192 $params[$key] = $dateValue;
195 CRM_Contact_Import_Parser_Contact
::addToErrorMsg('Activity date', $errorMessage);
199 elseif ($key == 'activity_engagement_level' && $val &&
200 !CRM_Utils_Rule
::positiveInteger($val)
202 CRM_Contact_Import_Parser_Contact
::addToErrorMsg('Activity Engagement Index', $errorMessage);
205 // Date-Format part ends.
207 // Checking error in custom data.
208 $params['contact_type'] = $this->_contactType ??
'Activity';
210 CRM_Contact_Import_Parser_Contact
::isErrorInCustomData($params, $errorMessage);
213 $tempMsg = "Invalid value for field(s) : $errorMessage";
214 array_unshift($values, $tempMsg);
215 $errorMessage = NULL;
216 return CRM_Import_Parser
::ERROR
;
219 return CRM_Import_Parser
::VALID
;
223 * Handle the values in import mode.
225 * @param int $onDuplicate
226 * The code for what action to take on duplicates.
227 * @param array $values
228 * The array of values belonging to this line.
231 * the result of this processing
233 public function import($onDuplicate, &$values) {
234 // First make sure this is a valid line
235 $response = $this->summary($values);
237 if ($response != CRM_Import_Parser
::VALID
) {
240 $params = &$this->getActiveFieldParams();
241 $activityLabel = array_search('activity_label', $this->_mapperKeys
);
242 if ($activityLabel) {
243 $params = array_merge($params, ['activity_label' => $values[$activityLabel]]);
246 $session = CRM_Core_Session
::singleton();
247 $dateType = $session->get('dateTypes');
248 if (!isset($params['source_contact_id'])) {
249 $params['source_contact_id'] = $session->get('userID');
252 $customFields = CRM_Core_BAO_CustomField
::getFields('Activity');
254 foreach ($params as $key => $val) {
255 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
256 if ($key == 'activity_date_time' && $val) {
257 $params[$key] = CRM_Utils_Date
::formatDate($val, $dateType);
259 elseif (!empty($customFields[$customFieldID]) && $customFields[$customFieldID]['data_type'] == 'Date') {
260 CRM_Contact_Import_Parser_Contact
::formatCustomDate($params, $params, $dateType, $key);
262 elseif (!empty($customFields[$customFieldID]) && $customFields[$customFieldID]['data_type'] == 'Boolean') {
263 $params[$key] = CRM_Utils_String
::strtoboolstr($val);
266 elseif ($key == 'activity_date_time') {
267 $params[$key] = CRM_Utils_Date
::formatDate($val, $dateType);
269 elseif ($key == 'activity_subject') {
270 $params['subject'] = $val;
273 // Date-Format part ends.
274 $formatError = $this->deprecated_activity_formatted_param($params, $params, TRUE);
277 array_unshift($values, $formatError['error_message']);
278 return CRM_Import_Parser
::ERROR
;
281 $params['custom'] = CRM_Core_BAO_CustomField
::postProcess($params,
286 if ($this->_contactIdIndex
< 0) {
288 // Retrieve contact id using contact dedupe rule.
289 // Since we are supporting only individual's activity import.
290 $params['contact_type'] = 'Individual';
291 $params['version'] = 3;
292 $error = _civicrm_api3_deprecated_duplicate_formatted_contact($params);
294 if (CRM_Core_Error
::isAPIError($error, CRM_Core_ERROR
::DUPLICATE_CONTACT
)) {
295 $matchedIDs = explode(',', $error['error_message']['params'][0]);
296 if (count($matchedIDs) > 1) {
297 array_unshift($values, 'Multiple matching contact records detected for this row. The activity was not imported');
298 return CRM_Import_Parser
::ERROR
;
300 $cid = $matchedIDs[0];
301 $params['target_contact_id'] = $cid;
302 $params['version'] = 3;
303 $newActivity = civicrm_api('activity', 'create', $params);
304 if (!empty($newActivity['is_error'])) {
305 array_unshift($values, $newActivity['error_message']);
306 return CRM_Import_Parser
::ERROR
;
309 $this->_newActivity
[] = $newActivity['id'];
310 return CRM_Import_Parser
::VALID
;
313 // Using new Dedupe rule.
315 'contact_type' => 'Individual',
316 'used' => 'Unsupervised',
318 $fieldsArray = CRM_Dedupe_BAO_Rule
::dedupeRuleFields($ruleParams);
321 foreach ($fieldsArray as $value) {
322 if (array_key_exists(trim($value), $params)) {
323 $paramValue = $params[trim($value)];
324 if (is_array($paramValue)) {
325 $disp .= $params[trim($value)][0][trim($value)] . " ";
328 $disp .= $params[trim($value)] . " ";
333 if (!empty($params['external_identifier'])) {
335 $disp .= "AND {$params['external_identifier']}";
338 $disp = $params['external_identifier'];
342 array_unshift($values, 'No matching Contact found for (' . $disp . ')');
343 return CRM_Import_Parser
::ERROR
;
345 if (!empty($params['external_identifier'])) {
346 $targetContactId = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
347 $params['external_identifier'], 'id', 'external_identifier'
350 if (!empty($params['target_contact_id']) &&
351 $params['target_contact_id'] != $targetContactId
353 array_unshift($values, 'Mismatch of External ID:' . $params['external_identifier'] . ' and Contact Id:' . $params['target_contact_id']);
354 return CRM_Import_Parser
::ERROR
;
356 if ($targetContactId) {
357 $params['target_contact_id'] = $targetContactId;
360 array_unshift($values, 'No Matching Contact for External ID:' . $params['external_identifier']);
361 return CRM_Import_Parser
::ERROR
;
365 $params['version'] = 3;
366 $newActivity = civicrm_api('activity', 'create', $params);
367 if (!empty($newActivity['is_error'])) {
368 array_unshift($values, $newActivity['error_message']);
369 return CRM_Import_Parser
::ERROR
;
372 $this->_newActivity
[] = $newActivity['id'];
373 return CRM_Import_Parser
::VALID
;
377 * take the input parameter list as specified in the data model and
378 * convert it into the same format that we use in QF and BAO object
380 * @param array $params
381 * Associative array of property name/value.
382 * pairs to insert in new contact.
383 * @param array $values
384 * The reformatted properties that we can use internally.
386 * @param array|bool $create Is the formatted Values array going to
387 * be used for CRM_Activity_BAO_Activity::create()
389 * @return array|CRM_Error
391 protected function deprecated_activity_formatted_param(&$params, &$values, $create = FALSE) {
392 // copy all the activity fields as is
393 $fields = CRM_Activity_DAO_Activity
::fields();
394 _civicrm_api3_store_values($fields, $params, $values);
396 require_once 'CRM/Core/OptionGroup.php';
397 $customFields = CRM_Core_BAO_CustomField
::getFields('Activity');
399 foreach ($params as $key => $value) {
400 // ignore empty values or empty arrays etc
401 if (CRM_Utils_System
::isNull($value)) {
405 //Handling Custom Data
406 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($key)) {
407 $values[$key] = $value;
408 $type = $customFields[$customFieldID]['html_type'];
409 if (CRM_Core_BAO_CustomField
::isSerialized($customFields[$customFieldID])) {
410 $values[$key] = CRM_Import_Parser
::unserializeCustomValue($customFieldID, $value, $type);
412 elseif ($type == 'Select' ||
$type == 'Radio') {
413 $customOption = CRM_Core_BAO_CustomOption
::getCustomOption($customFieldID, TRUE);
414 foreach ($customOption as $customFldID => $customValue) {
415 $val = $customValue['value'] ??
NULL;
416 $label = $customValue['label'] ??
NULL;
417 $label = strtolower($label);
418 $value = strtolower(trim($value));
419 if (($value == $label) ||
($value == strtolower($val))) {
420 $values[$key] = $val;
426 if ($key == 'target_contact_id') {
427 if (!CRM_Utils_Rule
::integer($value)) {
428 return civicrm_api3_create_error("contact_id not valid: $value");
430 $contactID = CRM_Core_DAO
::singleValueQuery("SELECT id FROM civicrm_contact WHERE id = $value");
432 return civicrm_api3_create_error("Invalid Contact ID: There is no contact record with contact_id = $value.");