Fix metadata on member export
[civicrm-core.git] / CRM / Member / Import / Parser / Membership.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 */
33
6a488035
TO
34/**
35 * class to parse membership csv files
36 */
37class CRM_Member_Import_Parser_Membership extends CRM_Member_Import_Parser {
38
39 protected $_mapperKeys;
40
6a488035
TO
41 private $_membershipTypeIndex;
42 private $_membershipStatusIndex;
43
14b9e069 44 /**
45 * Array of metadata for all available fields.
46 *
47 * @var array
48 */
49 protected $fieldMetadata = [];
50
6a488035 51 /**
ceb10dc7 52 * Array of successfully imported membership id's
6a488035 53 *
971e129b 54 * @var array
6a488035
TO
55 */
56 protected $_newMemberships;
57
58 /**
fe482240 59 * Class constructor.
c2b5a0af
EM
60 *
61 * @param $mapperKeys
6a488035 62 */
14b9e069 63 public function __construct($mapperKeys) {
6a488035 64 parent::__construct();
14b9e069 65 $this->_mapperKeys = $mapperKeys;
6a488035
TO
66 }
67
68 /**
100fef9d 69 * The initializer code, called before the processing
6a488035
TO
70 *
71 * @return void
6a488035 72 */
00be9182 73 public function init() {
14b9e069 74 $this->fieldMetadata = CRM_Member_BAO_Membership::importableFields($this->_contactType, FALSE);
6a488035 75
14b9e069 76 foreach ($this->fieldMetadata as $name => $field) {
77 // @todo - we don't really need to do all this.... fieldMetadata is just fine to use as is.
6a488035
TO
78 $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT);
79 $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//');
80 $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//');
81 $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']);
82 }
83
be2fb01f 84 $this->_newMemberships = [];
6a488035
TO
85
86 $this->setActiveFields($this->_mapperKeys);
87
88 // FIXME: we should do this in one place together with Form/MapField.php
6a488035
TO
89 $this->_membershipTypeIndex = -1;
90 $this->_membershipStatusIndex = -1;
91
92 $index = 0;
93 foreach ($this->_mapperKeys as $key) {
94 switch ($key) {
6a488035
TO
95
96 case 'membership_type_id':
97 $this->_membershipTypeIndex = $index;
98 break;
99
100 case 'status_id':
101 $this->_membershipStatusIndex = $index;
102 break;
103 }
104 $index++;
105 }
106 }
107
108 /**
fe482240 109 * Handle the values in mapField mode.
6a488035 110 *
b2363ea8
TO
111 * @param array $values
112 * The array of values belonging to this line.
6a488035 113 *
d5cc0fc2 114 * @return bool
6a488035 115 */
00be9182 116 public function mapField(&$values) {
a05662ef 117 return CRM_Import_Parser::VALID;
6a488035
TO
118 }
119
120 /**
fe482240 121 * Handle the values in preview mode.
6a488035 122 *
b2363ea8
TO
123 * @param array $values
124 * The array of values belonging to this line.
6a488035 125 *
d5cc0fc2 126 * @return bool
a6c01b45 127 * the result of this processing
6a488035 128 */
00be9182 129 public function preview(&$values) {
6a488035
TO
130 return $this->summary($values);
131 }
132
133 /**
fe482240 134 * Handle the values in summary mode.
6a488035 135 *
b2363ea8
TO
136 * @param array $values
137 * The array of values belonging to this line.
6a488035 138 *
d5cc0fc2 139 * @return bool
a6c01b45 140 * the result of this processing
6a488035 141 */
00be9182 142 public function summary(&$values) {
6a488035
TO
143 $erroneousField = NULL;
144 $response = $this->setActiveFieldValues($values, $erroneousField);
145
146 $errorRequired = FALSE;
147
148 if ($this->_membershipTypeIndex < 0) {
149 $errorRequired = TRUE;
150 }
151 else {
152 $errorRequired = !CRM_Utils_Array::value($this->_membershipTypeIndex, $values);
153 }
154
155 if ($errorRequired) {
156 array_unshift($values, ts('Missing required fields'));
a05662ef 157 return CRM_Import_Parser::ERROR;
6a488035
TO
158 }
159
04f72de8 160 $params = $this->getActiveFieldParams();
6a488035
TO
161 $errorMessage = NULL;
162
163 //To check whether start date or join date is provided
8cc574cf 164 if (empty($params['membership_start_date']) && empty($params['join_date'])) {
6a488035 165 $errorMessage = 'Membership Start Date is required to create a memberships.';
719a6fec 166 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Start Date', $errorMessage);
6a488035 167 }
6a488035
TO
168
169 //for date-Formats
170 $session = CRM_Core_Session::singleton();
171 $dateType = $session->get('dateTypes');
172 foreach ($params as $key => $val) {
173
174 if ($val) {
175 switch ($key) {
176 case 'join_date':
177 if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) {
178 if (!CRM_Utils_Rule::date($params[$key])) {
719a6fec 179 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Member Since', $errorMessage);
6a488035
TO
180 }
181 }
182 else {
719a6fec 183 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Member Since', $errorMessage);
6a488035
TO
184 }
185 break;
186
187 case 'membership_start_date':
188 if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) {
189 if (!CRM_Utils_Rule::date($params[$key])) {
719a6fec 190 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Start Date', $errorMessage);
6a488035
TO
191 }
192 }
193 else {
719a6fec 194 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Start Date', $errorMessage);
6a488035
TO
195 }
196 break;
197
198 case 'membership_end_date':
199 if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) {
200 if (!CRM_Utils_Rule::date($params[$key])) {
719a6fec 201 CRM_Contact_Import_Parser_Contact::addToErrorMsg('End date', $errorMessage);
6a488035
TO
202 }
203 }
204 else {
719a6fec 205 CRM_Contact_Import_Parser_Contact::addToErrorMsg('End date', $errorMessage);
6a488035
TO
206 }
207 break;
e136f704
O
208
209 case 'status_override_end_date':
210 if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) {
211 if (!CRM_Utils_Rule::date($params[$key])) {
212 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Status Override End Date', $errorMessage);
213 }
214 }
215 else {
216 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Status Override End Date', $errorMessage);
217 }
218 break;
6a488035
TO
219
220 case 'membership_type_id':
14b9e069 221 // @todo - squish into membership status - can use same lines here too.
6a488035
TO
222 $membershipTypes = CRM_Member_PseudoConstant::membershipType();
223 if (!CRM_Utils_Array::crmInArray($val, $membershipTypes) &&
224 !array_key_exists($val, $membershipTypes)
225 ) {
719a6fec 226 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Membership Type', $errorMessage);
6a488035
TO
227 }
228 break;
229
230 case 'status_id':
14b9e069 231 if (!empty($val) && !$this->parsePseudoConstantField($val, $this->fieldMetadata[$key])) {
719a6fec 232 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Membership Status', $errorMessage);
6a488035
TO
233 }
234 break;
235
236 case 'email':
237 if (!CRM_Utils_Rule::email($val)) {
719a6fec 238 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Email Address', $errorMessage);
6a488035
TO
239 }
240 }
241 }
242 }
243 //date-Format part ends
244
245 $params['contact_type'] = 'Membership';
246
247 //checking error in custom data
719a6fec 248 CRM_Contact_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage);
6a488035
TO
249
250 if ($errorMessage) {
251 $tempMsg = "Invalid value for field(s) : $errorMessage";
252 array_unshift($values, $tempMsg);
253 $errorMessage = NULL;
a05662ef 254 return CRM_Import_Parser::ERROR;
6a488035
TO
255 }
256
a05662ef 257 return CRM_Import_Parser::VALID;
6a488035
TO
258 }
259
260 /**
fe482240 261 * Handle the values in import mode.
6a488035 262 *
b2363ea8
TO
263 * @param int $onDuplicate
264 * The code for what action to take on duplicates.
265 * @param array $values
266 * The array of values belonging to this line.
6a488035 267 *
d5cc0fc2 268 * @return bool
a6c01b45 269 * the result of this processing
6a488035 270 */
00be9182 271 public function import($onDuplicate, &$values) {
92e4c2a5 272 try {
4f7b71ab 273 // first make sure this is a valid line
274 $response = $this->summary($values);
275 if ($response != CRM_Import_Parser::VALID) {
276 return $response;
277 }
6a488035 278
04f72de8 279 $params = $this->getActiveFieldParams();
6a488035 280
4f7b71ab 281 //assign join date equal to start date if join date is not provided
8cc574cf 282 if (empty($params['join_date']) && !empty($params['membership_start_date'])) {
4f7b71ab 283 $params['join_date'] = $params['membership_start_date'];
284 }
6a488035 285
353ffa53
TO
286 $session = CRM_Core_Session::singleton();
287 $dateType = $session->get('dateTypes');
be2fb01f 288 $formatted = [];
5981d156
JP
289 $customDataType = !empty($params['contact_type']) ? $params['contact_type'] : 'Membership';
290 $customFields = CRM_Core_BAO_CustomField::getFields($customDataType);
4f7b71ab 291
292 // don't add to recent items, CRM-4399
293 $formatted['skipRecentView'] = TRUE;
be2fb01f 294 $dateLabels = [
4f7b71ab 295 'join_date' => ts('Member Since'),
296 'membership_start_date' => ts('Start Date'),
297 'membership_end_date' => ts('End Date'),
be2fb01f 298 ];
4f7b71ab 299 foreach ($params as $key => $val) {
300 if ($val) {
301 switch ($key) {
302 case 'join_date':
303 case 'membership_start_date':
304 case 'membership_end_date':
305 if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) {
306 if (!CRM_Utils_Rule::date($params[$key])) {
307 CRM_Contact_Import_Parser_Contact::addToErrorMsg($dateLabels[$key], $errorMessage);
308 }
309 }
310 else {
87bbc876 311 CRM_Contact_Import_Parser_Contact::addToErrorMsg($dateLabels[$key], $errorMessage);
6a488035 312 }
4f7b71ab 313 break;
6a488035 314
4f7b71ab 315 case 'membership_type_id':
316 if (!is_numeric($val)) {
317 unset($params['membership_type_id']);
318 $params['membership_type'] = $val;
319 }
320 break;
6a488035 321
4f7b71ab 322 case 'status_id':
14b9e069 323 // @todo - we can do this based on the presence of 'pseudoconstant' in the metadata rather than field specific.
324 $params[$key] = $this->parsePseudoConstantField($val, $this->fieldMetadata[$key]);
4f7b71ab 325 break;
6a488035 326
8f67d99a 327 case 'member_is_override':
4f7b71ab 328 $params[$key] = CRM_Utils_String::strtobool($val);
329 break;
330 }
331 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
481a74f4 332 if ($customFields[$customFieldID]['data_type'] == 'Date') {
4f7b71ab 333 CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key);
334 unset($params[$key]);
0db6c3e1 335 }
481a74f4 336 elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') {
4f7b71ab 337 $params[$key] = CRM_Utils_String::strtoboolstr($val);
338 }
6a488035
TO
339 }
340 }
341 }
4f7b71ab 342 //date-Format part ends
6a488035 343
be2fb01f 344 $formatValues = [];
4f7b71ab 345 foreach ($params as $key => $field) {
346 if ($field == NULL || $field === '') {
347 continue;
348 }
6a488035 349
4f7b71ab 350 $formatValues[$key] = $field;
6a488035
TO
351 }
352
4f7b71ab 353 //format params to meet api v2 requirements.
354 //@todo find a way to test removing this formatting
355 $formatError = $this->membership_format_params($formatValues, $formatted, TRUE);
6a488035 356
4f7b71ab 357 if ($onDuplicate != CRM_Import_Parser::DUPLICATE_UPDATE) {
6a488035 358 $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted,
4f7b71ab 359 NULL,
6a488035
TO
360 'Membership'
361 );
4f7b71ab 362 }
363 else {
364 //fix for CRM-2219 Update Membership
365 // onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE
8f67d99a 366 if (!empty($formatted['member_is_override']) && empty($formatted['status_id'])) {
4f7b71ab 367 array_unshift($values, 'Required parameter missing: Status');
368 return CRM_Import_Parser::ERROR;
369 }
6a488035 370
1a9d4317 371 if (!empty($formatValues['membership_id'])) {
353ffa53 372 $dao = new CRM_Member_BAO_Membership();
4f7b71ab 373 $dao->id = $formatValues['membership_id'];
be2fb01f 374 $dates = ['join_date', 'start_date', 'end_date'];
4f7b71ab 375 foreach ($dates as $v) {
82cc6775 376 if (empty($formatted[$v])) {
4f7b71ab 377 $formatted[$v] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $formatValues['membership_id'], $v);
378 }
379 }
380
381 $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted,
4f7b71ab 382 $formatValues['membership_id'],
383 'Membership'
384 );
385 if ($dao->find(TRUE)) {
82cc6775
PN
386 if (empty($params['line_item']) && !empty($formatted['membership_type_id'])) {
387 CRM_Price_BAO_LineItem::getLineItemArray($formatted, NULL, 'membership', $formatted['membership_type_id']);
388 }
d75f2f47 389
f57cb50c
MWMC
390 // @todo stop passing $ids array (and put details in $formatted if required)
391 $ids = [
392 'membership' => $formatValues['membership_id'],
393 'userId' => $session->get('userID'),
394 ];
4f7b71ab 395 $newMembership = CRM_Member_BAO_Membership::create($formatted, $ids, TRUE);
396 if (civicrm_error($newMembership)) {
397 array_unshift($values, $newMembership['is_error'] . ' for Membership ID ' . $formatValues['membership_id'] . '. Row was skipped.');
398 return CRM_Import_Parser::ERROR;
399 }
400 else {
401 $this->_newMemberships[] = $newMembership->id;
402 return CRM_Import_Parser::VALID;
403 }
6a488035
TO
404 }
405 else {
4f7b71ab 406 array_unshift($values, 'Matching Membership record not found for Membership ID ' . $formatValues['membership_id'] . '. Row was skipped.');
407 return CRM_Import_Parser::ERROR;
6a488035
TO
408 }
409 }
6a488035 410 }
6a488035 411
4f7b71ab 412 //Format dates
413 $startDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('start_date', $formatted), '%Y-%m-%d');
353ffa53
TO
414 $endDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('end_date', $formatted), '%Y-%m-%d');
415 $joinDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('join_date', $formatted), '%Y-%m-%d');
6a488035 416
64679927 417 if (!$this->isContactIDColumnPresent()) {
56316747 418 $error = $this->checkContactDuplicate($formatValues);
6a488035 419
4f7b71ab 420 if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) {
421 $matchedIDs = explode(',', $error['error_message']['params'][0]);
422 if (count($matchedIDs) > 1) {
423 array_unshift($values, 'Multiple matching contact records detected for this row. The membership was not imported');
424 return CRM_Import_Parser::ERROR;
425 }
426 else {
427 $cid = $matchedIDs[0];
428 $formatted['contact_id'] = $cid;
429
430 //fix for CRM-1924
431 $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'],
432 $joinDate,
433 $startDate,
434 $endDate
435 );
436 self::formattedDates($calcDates, $formatted);
437
438 //fix for CRM-3570, exclude the statuses those having is_admin = 1
439 //now user can import is_admin if is override is true.
440 $excludeIsAdmin = FALSE;
8f67d99a 441 if (empty($formatted['member_is_override'])) {
4f7b71ab 442 $formatted['exclude_is_admin'] = $excludeIsAdmin = TRUE;
443 }
444 $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate,
445 $endDate,
446 $joinDate,
447 'today',
5f11bbcc
EM
448 $excludeIsAdmin,
449 $formatted['membership_type_id'],
450 $formatted
4f7b71ab 451 );
452
a7488080 453 if (empty($formatted['status_id'])) {
4f7b71ab 454 $formatted['status_id'] = $calcStatus['id'];
455 }
8f67d99a 456 elseif (empty($formatted['member_is_override'])) {
4f7b71ab 457 if (empty($calcStatus)) {
458 array_unshift($values, 'Status in import row (' . $formatValues['status_id'] . ') does not match calculated status based on your configured Membership Status Rules. Record was not imported.');
459 return CRM_Import_Parser::ERROR;
460 }
461 elseif ($formatted['status_id'] != $calcStatus['id']) {
462 //Status Hold" is either NOT mapped or is FALSE
463 array_unshift($values, 'Status in import row (' . $formatValues['status_id'] . ') does not match calculated status based on your configured Membership Status Rules (' . $calcStatus['name'] . '). Record was not imported.');
464 return CRM_Import_Parser::ERROR;
465 }
466 }
467
468 $newMembership = civicrm_api3('membership', 'create', $formatted);
469
470 $this->_newMemberships[] = $newMembership['id'];
471 return CRM_Import_Parser::VALID;
472 }
6a488035
TO
473 }
474 else {
4f7b71ab 475 // Using new Dedupe rule.
be2fb01f 476 $ruleParams = [
4f7b71ab 477 'contact_type' => $this->_contactType,
353ffa53 478 'used' => 'Unsupervised',
be2fb01f 479 ];
4f7b71ab 480 $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams);
481 $disp = '';
482
483 foreach ($fieldsArray as $value) {
484 if (array_key_exists(trim($value), $params)) {
485 $paramValue = $params[trim($value)];
486 if (is_array($paramValue)) {
487 $disp .= $params[trim($value)][0][trim($value)] . " ";
488 }
489 else {
490 $disp .= $params[trim($value)] . " ";
491 }
492 }
6a488035 493 }
6a488035 494
a7488080 495 if (!empty($params['external_identifier'])) {
4f7b71ab 496 if ($disp) {
497 $disp .= "AND {$params['external_identifier']}";
6a488035 498 }
4f7b71ab 499 else {
500 $disp = $params['external_identifier'];
6a488035
TO
501 }
502 }
503
4f7b71ab 504 array_unshift($values, 'No matching Contact found for (' . $disp . ')');
505 return CRM_Import_Parser::ERROR;
6a488035
TO
506 }
507 }
508 else {
a7488080 509 if (!empty($formatValues['external_identifier'])) {
4f7b71ab 510 $checkCid = new CRM_Contact_DAO_Contact();
511 $checkCid->external_identifier = $formatValues['external_identifier'];
512 $checkCid->find(TRUE);
513 if ($checkCid->id != $formatted['contact_id']) {
d79be26c 514 array_unshift($values, 'Mismatch of External ID:' . $formatValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id']);
4f7b71ab 515 return CRM_Import_Parser::ERROR;
6a488035
TO
516 }
517 }
518
4f7b71ab 519 //to calculate dates
520 $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'],
521 $joinDate,
522 $startDate,
523 $endDate
524 );
525 self::formattedDates($calcDates, $formatted);
526 //end of date calculation part
527
528 //fix for CRM-3570, exclude the statuses those having is_admin = 1
529 //now user can import is_admin if is override is true.
530 $excludeIsAdmin = FALSE;
8f67d99a 531 if (empty($formatted['member_is_override'])) {
4f7b71ab 532 $formatted['exclude_is_admin'] = $excludeIsAdmin = TRUE;
533 }
534 $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate,
535 $endDate,
536 $joinDate,
537 'today',
5f11bbcc
EM
538 $excludeIsAdmin,
539 $formatted['membership_type_id'],
540 $formatted
4f7b71ab 541 );
a7488080 542 if (empty($formatted['status_id'])) {
4f7b71ab 543 $formatted['status_id'] = CRM_Utils_Array::value('id', $calcStatus);
544 }
8f67d99a 545 elseif (empty($formatted['member_is_override'])) {
4f7b71ab 546 if (empty($calcStatus)) {
547 array_unshift($values, 'Status in import row (' . CRM_Utils_Array::value('status_id', $formatValues) . ') does not match calculated status based on your configured Membership Status Rules. Record was not imported.');
548 return CRM_Import_Parser::ERROR;
6a488035 549 }
4f7b71ab 550 elseif ($formatted['status_id'] != $calcStatus['id']) {
551 //Status Hold" is either NOT mapped or is FALSE
552 array_unshift($values, 'Status in import row (' . CRM_Utils_Array::value('status_id', $formatValues) . ') does not match calculated status based on your configured Membership Status Rules (' . $calcStatus['name'] . '). Record was not imported.');
553 return CRM_Import_Parser::ERROR;
6a488035
TO
554 }
555 }
556
4f7b71ab 557 $newMembership = civicrm_api3('membership', 'create', $formatted);
6a488035 558
4f7b71ab 559 $this->_newMemberships[] = $newMembership['id'];
560 return CRM_Import_Parser::VALID;
6a488035 561 }
f719e41c 562 }
563 catch (Exception $e) {
564 array_unshift($values, $e->getMessage());
565 return CRM_Import_Parser::ERROR;
566 }
6a488035
TO
567 }
568
569 /**
ceb10dc7 570 * Get the array of successfully imported membership id's
6a488035
TO
571 *
572 * @return array
6a488035 573 */
00be9182 574 public function &getImportedMemberships() {
6a488035
TO
575 return $this->_newMemberships;
576 }
577
578 /**
100fef9d 579 * The initializer code, called before the processing
6a488035
TO
580 *
581 * @return void
6a488035 582 */
b09fe5ed
TO
583 public function fini() {
584 }
6a488035
TO
585
586 /**
587 * to calculate join, start and end dates
588 *
b2363ea8
TO
589 * @param array $calcDates
590 * Array of dates returned by getDatesForMembershipType().
6a488035 591 *
2a6da8d7 592 * @param $formatted
6a488035 593 *
6a488035 594 */
00be9182 595 public function formattedDates($calcDates, &$formatted) {
be2fb01f 596 $dates = [
6a488035
TO
597 'join_date',
598 'start_date',
599 'end_date',
be2fb01f 600 ];
6a488035
TO
601
602 foreach ($dates as $d) {
603 if (isset($formatted[$d]) &&
604 !CRM_Utils_System::isNull($formatted[$d])
605 ) {
606 $formatted[$d] = CRM_Utils_Date::isoToMysql($formatted[$d]);
607 }
608 elseif (isset($calcDates[$d])) {
609 $formatted[$d] = CRM_Utils_Date::isoToMysql($calcDates[$d]);
610 }
611 }
612 }
77b97be7 613
3c15495c 614 /**
615 * @deprecated - this function formats params according to v2 standards but
616 * need to be sure about the impact of not calling it so retaining on the import class
617 * take the input parameter list as specified in the data model and
618 * convert it into the same format that we use in QF and BAO object
619 *
b2363ea8
TO
620 * @param array $params
621 * Associative array of property name/value.
3c15495c 622 * pairs to insert in new contact.
b2363ea8
TO
623 * @param array $values
624 * The reformatted properties that we can use internally.
3c15495c 625 *
77b97be7 626 * @param array|bool $create Is the formatted Values array going to
3c15495c 627 * be used for CRM_Member_BAO_Membership:create()
628 *
77b97be7 629 * @throws Exception
3c15495c 630 * @return array|error
3c15495c 631 */
00be9182 632 public function membership_format_params($params, &$values, $create = FALSE) {
3c15495c 633 require_once 'api/v3/utils.php';
634 $fields = CRM_Member_DAO_Membership::fields();
635 _civicrm_api3_store_values($fields, $params, $values);
636
481a74f4 637 $customFields = CRM_Core_BAO_CustomField::getFields('Membership');
3c15495c 638
639 foreach ($params as $key => $value) {
640 // ignore empty values or empty arrays etc
641 if (CRM_Utils_System::isNull($value)) {
642 continue;
643 }
644
645 //Handling Custom Data
646 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
647 $values[$key] = $value;
648 $type = $customFields[$customFieldID]['html_type'];
6cc845ad 649 if ($type == 'CheckBox' || $type == 'Multi-Select') {
481a74f4 650 $mulValues = explode(',', $value);
b09fe5ed 651 $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE);
be2fb01f 652 $values[$key] = [];
481a74f4 653 foreach ($mulValues as $v1) {
22e263ad 654 foreach ($customOption as $customValueID => $customLabel) {
3c15495c 655 $customValue = $customLabel['value'];
481a74f4 656 if ((strtolower($customLabel['label']) == strtolower(trim($v1))) ||
353ffa53
TO
657 (strtolower($customValue) == strtolower(trim($v1)))
658 ) {
481a74f4 659 if ($type == 'CheckBox') {
3c15495c 660 $values[$key][$customValue] = 1;
0db6c3e1
TO
661 }
662 else {
3c15495c 663 $values[$key][] = $customValue;
664 }
665 }
666 }
667 }
668 }
669 }
670
671 switch ($key) {
672 case 'membership_contact_id':
673 if (!CRM_Utils_Rule::integer($value)) {
f719e41c 674 throw new Exception("contact_id not valid: $value");
3c15495c 675 }
353ffa53 676 $dao = new CRM_Core_DAO();
be2fb01f 677 $qParams = [];
353ffa53 678 $svq = $dao->singleValueQuery("SELECT id FROM civicrm_contact WHERE id = $value",
3c15495c 679 $qParams
680 );
681 if (!$svq) {
f719e41c 682 throw new Exception("Invalid Contact ID: There is no contact record with contact_id = $value.");
3c15495c 683 }
684 $values['contact_id'] = $values['membership_contact_id'];
685 unset($values['membership_contact_id']);
686 break;
687
688 case 'membership_type_id':
689 if (!CRM_Utils_Array::value($value, CRM_Member_PseudoConstant::membershipType())) {
f719e41c 690 throw new Exception('Invalid Membership Type Id');
3c15495c 691 }
692 $values[$key] = $value;
693 break;
694
695 case 'membership_type':
696 $membershipTypeId = CRM_Utils_Array::key(ucfirst($value),
353ffa53 697 CRM_Member_PseudoConstant::membershipType()
3c15495c 698 );
699 if ($membershipTypeId) {
a7488080 700 if (!empty($values['membership_type_id']) &&
3c15495c 701 $membershipTypeId != $values['membership_type_id']
702 ) {
f719e41c 703 throw new Exception('Mismatched membership Type and Membership Type Id');
3c15495c 704 }
705 }
706 else {
f719e41c 707 throw new Exception('Invalid Membership Type');
3c15495c 708 }
709 $values['membership_type_id'] = $membershipTypeId;
710 break;
711
3c15495c 712 default:
713 break;
714 }
715 }
716
717 _civicrm_api3_custom_format_params($params, $values, 'Membership');
718
3c15495c 719 if ($create) {
720 // CRM_Member_BAO_Membership::create() handles membership_start_date,
721 // membership_end_date and membership_source. So, if $values contains
722 // membership_start_date, membership_end_date or membership_source,
723 // convert it to start_date, end_date or source
be2fb01f 724 $changes = [
3c15495c 725 'membership_start_date' => 'start_date',
726 'membership_end_date' => 'end_date',
727 'membership_source' => 'source',
be2fb01f 728 ];
3c15495c 729
730 foreach ($changes as $orgVal => $changeVal) {
731 if (isset($values[$orgVal])) {
732 $values[$changeVal] = $values[$orgVal];
733 unset($values[$orgVal]);
734 }
735 }
736 }
737
738 return NULL;
739 }
96025800 740
64679927 741 /**
742 * Is the contact ID mapped.
743 *
744 * @return bool
745 */
746 protected function isContactIDColumnPresent(): bool {
747 return in_array('membership_contact_id', $this->_mapperKeys, TRUE);
748 }
749
6a488035 750}