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