Commit | Line | Data |
---|---|---|
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 | */ | |
ca4caf13 | 21 | class CRM_Member_Import_Parser_Membership extends CRM_Import_Parser { |
6a488035 TO |
22 | |
23 | protected $_mapperKeys; | |
24 | ||
14b9e069 | 25 | /** |
26 | * Array of metadata for all available fields. | |
27 | * | |
28 | * @var array | |
29 | */ | |
30 | protected $fieldMetadata = []; | |
31 | ||
6a488035 | 32 | /** |
ceb10dc7 | 33 | * Array of successfully imported membership id's |
6a488035 | 34 | * |
971e129b | 35 | * @var array |
6a488035 TO |
36 | */ |
37 | protected $_newMemberships; | |
38 | ||
ca4caf13 EM |
39 | protected $_fileName; |
40 | ||
41 | /** | |
42 | * Imported file size | |
43 | * @var int | |
44 | */ | |
45 | protected $_fileSize; | |
46 | ||
47 | /** | |
48 | * Separator being used | |
49 | * @var string | |
50 | */ | |
51 | protected $_separator; | |
52 | ||
53 | /** | |
54 | * Total number of lines in file | |
55 | * @var int | |
56 | */ | |
57 | protected $_lineCount; | |
58 | ||
6a488035 | 59 | /** |
fe482240 | 60 | * Class constructor. |
c2b5a0af EM |
61 | * |
62 | * @param $mapperKeys | |
6a488035 | 63 | */ |
c2d1c1c2 | 64 | public function __construct($mapperKeys = []) { |
6a488035 | 65 | parent::__construct(); |
14b9e069 | 66 | $this->_mapperKeys = $mapperKeys; |
6a488035 TO |
67 | } |
68 | ||
ca4caf13 EM |
69 | /** |
70 | * @param string $fileName | |
71 | * @param string $separator | |
72 | * @param $mapper | |
73 | * @param bool $skipColumnHeader | |
74 | * @param int $mode | |
75 | * @param int $contactType | |
76 | * @param int $onDuplicate | |
77 | * @param int $statusID | |
ca4caf13 EM |
78 | * |
79 | * @return mixed | |
80 | * @throws Exception | |
81 | */ | |
82 | public function run( | |
83 | $fileName, | |
84 | $separator, | |
85 | $mapper, | |
86 | $skipColumnHeader = FALSE, | |
87 | $mode = self::MODE_PREVIEW, | |
88 | $contactType = self::CONTACT_INDIVIDUAL, | |
89 | $onDuplicate = self::DUPLICATE_SKIP, | |
b584b608 | 90 | $statusID = NULL |
ca4caf13 | 91 | ) { |
b584b608 | 92 | $this->_contactType = $this->getContactType(); |
ca4caf13 EM |
93 | $this->init(); |
94 | ||
06ef1cdc | 95 | $this->_lineCount = 0; |
ca4caf13 | 96 | $this->_invalidRowCount = $this->_validCount = 0; |
da8d3d49 | 97 | $this->_totalCount = 0; |
ca4caf13 EM |
98 | |
99 | $this->_errors = []; | |
100 | $this->_warnings = []; | |
ca4caf13 EM |
101 | if ($statusID) { |
102 | $this->progressImport($statusID); | |
103 | $startTimestamp = $currTimestamp = $prevTimestamp = CRM_Utils_Time::time(); | |
104 | } | |
b584b608 EM |
105 | $dataSource = $this->getDataSourceObject(); |
106 | $totalRowCount = $dataSource->getRowCount(['new']); | |
107 | $dataSource->setStatuses(['new']); | |
108 | while ($row = $dataSource->getRow()) { | |
109 | $values = array_values($row); | |
22f90136 | 110 | if ($mode == self::MODE_IMPORT) { |
2d306c45 | 111 | $this->import($values); |
ca4caf13 EM |
112 | if ($statusID && (($this->_lineCount % 50) == 0)) { |
113 | $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount); | |
114 | } | |
115 | } | |
ca4caf13 | 116 | } |
ca4caf13 EM |
117 | } |
118 | ||
119 | /** | |
120 | * Given a list of the importable field keys that the user has selected | |
121 | * set the active fields array to this list | |
122 | * | |
123 | * @param array $fieldKeys mapped array of values | |
124 | * | |
125 | * @return void | |
126 | */ | |
127 | public function setActiveFields($fieldKeys) { | |
128 | $this->_activeFieldCount = count($fieldKeys); | |
129 | foreach ($fieldKeys as $key) { | |
130 | if (empty($this->_fields[$key])) { | |
131 | $this->_activeFields[] = new CRM_Member_Import_Field('', ts('- do not import -')); | |
132 | } | |
133 | else { | |
134 | $this->_activeFields[] = clone($this->_fields[$key]); | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
139 | /** | |
140 | * Format the field values for input to the api. | |
141 | * | |
142 | * @return array | |
143 | * (reference ) associative array of name/value pairs | |
144 | */ | |
209cedd9 EM |
145 | public function getParams() { |
146 | $this->getSubmittedValue('mapper'); | |
ca4caf13 EM |
147 | $params = []; |
148 | for ($i = 0; $i < $this->_activeFieldCount; $i++) { | |
149 | if (isset($this->_activeFields[$i]->_value) | |
150 | && !isset($params[$this->_activeFields[$i]->_name]) | |
151 | && !isset($this->_activeFields[$i]->_related) | |
152 | ) { | |
153 | ||
154 | $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value; | |
155 | } | |
156 | } | |
157 | return $params; | |
158 | } | |
159 | ||
160 | /** | |
161 | * @param string $name | |
162 | * @param $title | |
163 | * @param int $type | |
164 | * @param string $headerPattern | |
165 | * @param string $dataPattern | |
166 | */ | |
167 | public function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') { | |
168 | if (empty($name)) { | |
169 | $this->_fields['doNotImport'] = new CRM_Member_Import_Field($name, $title, $type, $headerPattern, $dataPattern); | |
170 | } | |
171 | else { | |
172 | ||
173 | //$tempField = CRM_Contact_BAO_Contact::importableFields('Individual', null ); | |
174 | $tempField = CRM_Contact_BAO_Contact::importableFields('All', NULL); | |
175 | if (!array_key_exists($name, $tempField)) { | |
176 | $this->_fields[$name] = new CRM_Member_Import_Field($name, $title, $type, $headerPattern, $dataPattern); | |
177 | } | |
178 | else { | |
179 | $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, | |
180 | CRM_Utils_Array::value('hasLocationType', $tempField[$name]) | |
181 | ); | |
182 | } | |
183 | } | |
184 | } | |
185 | ||
186 | /** | |
187 | * Store parser values. | |
188 | * | |
189 | * @param CRM_Core_Session $store | |
190 | * | |
191 | * @param int $mode | |
192 | * | |
193 | * @return void | |
194 | */ | |
195 | public function set($store, $mode = self::MODE_SUMMARY) { | |
ca4caf13 | 196 | $store->set('lineCount', $this->_lineCount); |
ca4caf13 EM |
197 | $store->set('validRowCount', $this->_validCount); |
198 | $store->set('invalidRowCount', $this->_invalidRowCount); | |
ca4caf13 | 199 | |
ca4caf13 EM |
200 | if ($this->_invalidRowCount) { |
201 | $store->set('errorsFileName', $this->_errorFileName); | |
202 | } | |
ca4caf13 EM |
203 | |
204 | if ($mode == self::MODE_IMPORT) { | |
205 | $store->set('duplicateRowCount', $this->_duplicateCount); | |
206 | if ($this->_duplicateCount) { | |
207 | $store->set('duplicatesFileName', $this->_duplicateFileName); | |
208 | } | |
209 | } | |
210 | } | |
211 | ||
212 | /** | |
213 | * Export data to a CSV file. | |
214 | * | |
215 | * @param string $fileName | |
216 | * @param array $header | |
217 | * @param array $data | |
218 | * | |
219 | * @return void | |
220 | */ | |
221 | public static function exportCSV($fileName, $header, $data) { | |
222 | $output = []; | |
223 | $fd = fopen($fileName, 'w'); | |
224 | ||
225 | foreach ($header as $key => $value) { | |
226 | $header[$key] = "\"$value\""; | |
227 | } | |
228 | $config = CRM_Core_Config::singleton(); | |
229 | $output[] = implode($config->fieldSeparator, $header); | |
230 | ||
231 | foreach ($data as $datum) { | |
232 | foreach ($datum as $key => $value) { | |
233 | if (is_array($value)) { | |
234 | foreach ($value[0] as $k1 => $v1) { | |
235 | if ($k1 == 'location_type_id') { | |
236 | continue; | |
237 | } | |
238 | $datum[$k1] = $v1; | |
239 | } | |
240 | } | |
241 | else { | |
242 | $datum[$key] = "\"$value\""; | |
243 | } | |
244 | } | |
245 | $output[] = implode($config->fieldSeparator, $datum); | |
246 | } | |
247 | fwrite($fd, implode("\n", $output)); | |
248 | fclose($fd); | |
249 | } | |
250 | ||
6a488035 | 251 | /** |
100fef9d | 252 | * The initializer code, called before the processing |
6a488035 TO |
253 | * |
254 | * @return void | |
6a488035 | 255 | */ |
00be9182 | 256 | public function init() { |
af05126d EM |
257 | // Force re-load of user job. |
258 | unset($this->userJob); | |
d8844db5 | 259 | $this->setFieldMetadata(); |
6a488035 | 260 | |
be2fb01f | 261 | $this->_newMemberships = []; |
6a488035 TO |
262 | |
263 | $this->setActiveFields($this->_mapperKeys); | |
6a488035 TO |
264 | } |
265 | ||
6a488035 | 266 | /** |
22f90136 | 267 | * Validate the values. |
6a488035 | 268 | * |
b2363ea8 TO |
269 | * @param array $values |
270 | * The array of values belonging to this line. | |
6a488035 | 271 | */ |
79e1afb8 | 272 | public function validateValues($values): void { |
209cedd9 | 273 | $params = $this->getMappedRow($values); |
22f90136 EM |
274 | $errors = []; |
275 | foreach ($params as $key => $value) { | |
276 | $errors = array_merge($this->getInvalidValues($value, $key), $errors); | |
277 | } | |
1006edc9 | 278 | |
209cedd9 | 279 | if (empty($params['membership_type_id'])) { |
22f90136 | 280 | $errors[] = ts('Missing required fields'); |
79e1afb8 | 281 | return; |
6a488035 | 282 | } |
6a488035 TO |
283 | |
284 | //To check whether start date or join date is provided | |
209cedd9 | 285 | if (empty($params['start_date']) && empty($params['join_date'])) { |
22f90136 | 286 | $errors[] = 'Membership Start Date is required to create a memberships.'; |
6a488035 | 287 | } |
22f90136 EM |
288 | if ($errors) { |
289 | throw new CRM_Core_Exception('Invalid value for field(s) : ' . implode(',', $errors)); | |
6a488035 | 290 | } |
6a488035 TO |
291 | } |
292 | ||
293 | /** | |
fe482240 | 294 | * Handle the values in import mode. |
6a488035 | 295 | * |
b2363ea8 TO |
296 | * @param array $values |
297 | * The array of values belonging to this line. | |
6a488035 | 298 | * |
2d306c45 EM |
299 | * @return int|void|null |
300 | * the result of this processing - which is ignored | |
6a488035 | 301 | */ |
2d306c45 EM |
302 | public function import($values) { |
303 | $onDuplicate = $this->getSubmittedValue('onDuplicate'); | |
22f90136 | 304 | $rowNumber = (int) ($values[array_key_last($values)]); |
92e4c2a5 | 305 | try { |
209cedd9 | 306 | $params = $this->getMappedRow($values); |
6a488035 | 307 | |
4f7b71ab | 308 | //assign join date equal to start date if join date is not provided |
209cedd9 EM |
309 | if (empty($params['join_date']) && !empty($params['start_date'])) { |
310 | $params['join_date'] = $params['start_date']; | |
4f7b71ab | 311 | } |
6a488035 | 312 | |
209cedd9 | 313 | $formatted = $params; |
4f7b71ab | 314 | // don't add to recent items, CRM-4399 |
315 | $formatted['skipRecentView'] = TRUE; | |
6a488035 | 316 | |
be2fb01f | 317 | $formatValues = []; |
4f7b71ab | 318 | foreach ($params as $key => $field) { |
19cea1b4 | 319 | // ignore empty values or empty arrays etc |
320 | if (CRM_Utils_System::isNull($field)) { | |
4f7b71ab | 321 | continue; |
322 | } | |
6a488035 | 323 | |
4f7b71ab | 324 | $formatValues[$key] = $field; |
6a488035 TO |
325 | } |
326 | ||
4f7b71ab | 327 | //format params to meet api v2 requirements. |
328 | //@todo find a way to test removing this formatting | |
329 | $formatError = $this->membership_format_params($formatValues, $formatted, TRUE); | |
6a488035 | 330 | |
4f7b71ab | 331 | if ($onDuplicate != CRM_Import_Parser::DUPLICATE_UPDATE) { |
6a488035 | 332 | $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, |
4f7b71ab | 333 | NULL, |
6a488035 TO |
334 | 'Membership' |
335 | ); | |
4f7b71ab | 336 | } |
337 | else { | |
338 | //fix for CRM-2219 Update Membership | |
339 | // onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE | |
209cedd9 | 340 | if (!empty($formatted['is_override']) && empty($formatted['status_id'])) { |
2d306c45 | 341 | throw new CRM_Core_Exception('Required parameter missing: Status', CRM_Import_Parser::ERROR); |
4f7b71ab | 342 | } |
6a488035 | 343 | |
1a9d4317 | 344 | if (!empty($formatValues['membership_id'])) { |
353ffa53 | 345 | $dao = new CRM_Member_BAO_Membership(); |
4f7b71ab | 346 | $dao->id = $formatValues['membership_id']; |
be2fb01f | 347 | $dates = ['join_date', 'start_date', 'end_date']; |
4f7b71ab | 348 | foreach ($dates as $v) { |
82cc6775 | 349 | if (empty($formatted[$v])) { |
4f7b71ab | 350 | $formatted[$v] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $formatValues['membership_id'], $v); |
351 | } | |
352 | } | |
353 | ||
354 | $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, | |
4f7b71ab | 355 | $formatValues['membership_id'], |
356 | 'Membership' | |
357 | ); | |
358 | if ($dao->find(TRUE)) { | |
82cc6775 PN |
359 | if (empty($params['line_item']) && !empty($formatted['membership_type_id'])) { |
360 | CRM_Price_BAO_LineItem::getLineItemArray($formatted, NULL, 'membership', $formatted['membership_type_id']); | |
361 | } | |
d75f2f47 | 362 | |
f3a5127d | 363 | $newMembership = civicrm_api3('Membership', 'create', $formatted); |
364 | $this->_newMemberships[] = $newMembership['id']; | |
22f90136 | 365 | $this->setImportStatus($rowNumber, 'IMPORTED', 'Required parameter missing: Status'); |
f3a5127d | 366 | return CRM_Import_Parser::VALID; |
6a488035 | 367 | } |
2d306c45 | 368 | throw new CRM_Core_Exception('Matching Membership record not found for Membership ID ' . $formatValues['membership_id'] . '. Row was skipped.', CRM_Import_Parser::ERROR); |
6a488035 | 369 | } |
6a488035 | 370 | } |
6a488035 | 371 | |
4f7b71ab | 372 | //Format dates |
397ed960 EM |
373 | $startDate = $formatted['start_date']; |
374 | $endDate = $formatted['end_date'] ?? NULL; | |
375 | $joinDate = $formatted['join_date']; | |
6a488035 | 376 | |
397ed960 | 377 | if (empty($formatValues['id']) && empty($formatValues['contact_id'])) { |
56316747 | 378 | $error = $this->checkContactDuplicate($formatValues); |
6a488035 | 379 | |
4f7b71ab | 380 | if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) { |
381 | $matchedIDs = explode(',', $error['error_message']['params'][0]); | |
382 | if (count($matchedIDs) > 1) { | |
2d306c45 | 383 | throw new CRM_Core_Exception('Multiple matching contact records detected for this row. The membership was not imported', CRM_Import_Parser::ERROR); |
4f7b71ab | 384 | } |
385 | else { | |
386 | $cid = $matchedIDs[0]; | |
387 | $formatted['contact_id'] = $cid; | |
388 | ||
389 | //fix for CRM-1924 | |
390 | $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'], | |
391 | $joinDate, | |
392 | $startDate, | |
393 | $endDate | |
394 | ); | |
395 | self::formattedDates($calcDates, $formatted); | |
396 | ||
397 | //fix for CRM-3570, exclude the statuses those having is_admin = 1 | |
398 | //now user can import is_admin if is override is true. | |
399 | $excludeIsAdmin = FALSE; | |
209cedd9 | 400 | if (empty($formatted['is_override'])) { |
4f7b71ab | 401 | $formatted['exclude_is_admin'] = $excludeIsAdmin = TRUE; |
402 | } | |
403 | $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate, | |
404 | $endDate, | |
405 | $joinDate, | |
2cb64970 | 406 | 'now', |
5f11bbcc EM |
407 | $excludeIsAdmin, |
408 | $formatted['membership_type_id'], | |
409 | $formatted | |
4f7b71ab | 410 | ); |
411 | ||
a7488080 | 412 | if (empty($formatted['status_id'])) { |
4f7b71ab | 413 | $formatted['status_id'] = $calcStatus['id']; |
414 | } | |
209cedd9 | 415 | elseif (empty($formatted['is_override'])) { |
4f7b71ab | 416 | if (empty($calcStatus)) { |
2d306c45 | 417 | throw new CRM_Core_Exception('Status in import row (' . $formatValues['status_id'] . ') does not match calculated status based on your configured Membership Status Rules. Record was not imported.', CRM_Import_Parser::ERROR); |
4f7b71ab | 418 | } |
22f90136 | 419 | if ($formatted['status_id'] != $calcStatus['id']) { |
4f7b71ab | 420 | //Status Hold" is either NOT mapped or is FALSE |
2d306c45 | 421 | throw new CRM_Core_Exception('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.', CRM_Import_Parser::ERROR); |
4f7b71ab | 422 | } |
423 | } | |
424 | ||
425 | $newMembership = civicrm_api3('membership', 'create', $formatted); | |
426 | ||
427 | $this->_newMemberships[] = $newMembership['id']; | |
22f90136 | 428 | $this->setImportStatus($rowNumber, 'IMPORTED', ''); |
4f7b71ab | 429 | return CRM_Import_Parser::VALID; |
430 | } | |
6a488035 TO |
431 | } |
432 | else { | |
4f7b71ab | 433 | // Using new Dedupe rule. |
be2fb01f | 434 | $ruleParams = [ |
4f7b71ab | 435 | 'contact_type' => $this->_contactType, |
353ffa53 | 436 | 'used' => 'Unsupervised', |
be2fb01f | 437 | ]; |
61194d45 | 438 | $fieldsArray = CRM_Dedupe_BAO_DedupeRule::dedupeRuleFields($ruleParams); |
4f7b71ab | 439 | $disp = ''; |
440 | ||
441 | foreach ($fieldsArray as $value) { | |
442 | if (array_key_exists(trim($value), $params)) { | |
443 | $paramValue = $params[trim($value)]; | |
444 | if (is_array($paramValue)) { | |
445 | $disp .= $params[trim($value)][0][trim($value)] . " "; | |
446 | } | |
447 | else { | |
448 | $disp .= $params[trim($value)] . " "; | |
449 | } | |
450 | } | |
6a488035 | 451 | } |
6a488035 | 452 | |
a7488080 | 453 | if (!empty($params['external_identifier'])) { |
4f7b71ab | 454 | if ($disp) { |
455 | $disp .= "AND {$params['external_identifier']}"; | |
6a488035 | 456 | } |
4f7b71ab | 457 | else { |
458 | $disp = $params['external_identifier']; | |
6a488035 TO |
459 | } |
460 | } | |
2d306c45 | 461 | throw new CRM_Core_Exception('No matching Contact found for (' . $disp . ')', CRM_Import_Parser::ERROR); |
6a488035 TO |
462 | } |
463 | } | |
464 | else { | |
a7488080 | 465 | if (!empty($formatValues['external_identifier'])) { |
4f7b71ab | 466 | $checkCid = new CRM_Contact_DAO_Contact(); |
467 | $checkCid->external_identifier = $formatValues['external_identifier']; | |
468 | $checkCid->find(TRUE); | |
469 | if ($checkCid->id != $formatted['contact_id']) { | |
2d306c45 | 470 | throw new CRM_Core_Exception('Mismatch of External ID:' . $formatValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id'], CRM_Import_Parser::ERROR); |
6a488035 TO |
471 | } |
472 | } | |
473 | ||
4f7b71ab | 474 | //to calculate dates |
475 | $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'], | |
476 | $joinDate, | |
477 | $startDate, | |
478 | $endDate | |
479 | ); | |
480 | self::formattedDates($calcDates, $formatted); | |
481 | //end of date calculation part | |
482 | ||
483 | //fix for CRM-3570, exclude the statuses those having is_admin = 1 | |
484 | //now user can import is_admin if is override is true. | |
485 | $excludeIsAdmin = FALSE; | |
209cedd9 | 486 | if (empty($formatted['is_override'])) { |
4f7b71ab | 487 | $formatted['exclude_is_admin'] = $excludeIsAdmin = TRUE; |
488 | } | |
489 | $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate, | |
490 | $endDate, | |
491 | $joinDate, | |
2cb64970 | 492 | 'now', |
5f11bbcc EM |
493 | $excludeIsAdmin, |
494 | $formatted['membership_type_id'], | |
495 | $formatted | |
4f7b71ab | 496 | ); |
a7488080 | 497 | if (empty($formatted['status_id'])) { |
9c1bc317 | 498 | $formatted['status_id'] = $calcStatus['id'] ?? NULL; |
4f7b71ab | 499 | } |
209cedd9 | 500 | elseif (empty($formatted['is_override'])) { |
4f7b71ab | 501 | if (empty($calcStatus)) { |
2d306c45 | 502 | throw new CRM_Core_Exception('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.', CRM_Import_Parser::ERROR); |
6a488035 | 503 | } |
2d306c45 | 504 | if ($formatted['status_id'] != $calcStatus['id']) { |
4f7b71ab | 505 | //Status Hold" is either NOT mapped or is FALSE |
2d306c45 | 506 | throw new CRM_Core_Exception($rowNumber, 'ERROR', '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.', CRM_Import_Parser::ERROR); |
6a488035 TO |
507 | } |
508 | } | |
509 | ||
4f7b71ab | 510 | $newMembership = civicrm_api3('membership', 'create', $formatted); |
6a488035 | 511 | |
4f7b71ab | 512 | $this->_newMemberships[] = $newMembership['id']; |
22f90136 | 513 | $this->setImportStatus($rowNumber, 'IMPORTED', ''); |
4f7b71ab | 514 | return CRM_Import_Parser::VALID; |
6a488035 | 515 | } |
f719e41c | 516 | } |
2d306c45 EM |
517 | catch (CRM_Core_Exception $e) { |
518 | $this->setImportStatus($rowNumber, 'ERROR', $e->getMessage()); | |
519 | return CRM_Import_Parser::ERROR; | |
520 | } | |
521 | catch (CiviCRM_API3_Exception $e) { | |
22f90136 | 522 | $this->setImportStatus($rowNumber, 'ERROR', $e->getMessage()); |
f719e41c | 523 | return CRM_Import_Parser::ERROR; |
524 | } | |
6a488035 TO |
525 | } |
526 | ||
527 | /** | |
ceb10dc7 | 528 | * Get the array of successfully imported membership id's |
6a488035 TO |
529 | * |
530 | * @return array | |
6a488035 | 531 | */ |
00be9182 | 532 | public function &getImportedMemberships() { |
6a488035 TO |
533 | return $this->_newMemberships; |
534 | } | |
535 | ||
6a488035 TO |
536 | /** |
537 | * to calculate join, start and end dates | |
538 | * | |
b2363ea8 TO |
539 | * @param array $calcDates |
540 | * Array of dates returned by getDatesForMembershipType(). | |
6a488035 | 541 | * |
2a6da8d7 | 542 | * @param $formatted |
6a488035 | 543 | * |
6a488035 | 544 | */ |
00be9182 | 545 | public function formattedDates($calcDates, &$formatted) { |
be2fb01f | 546 | $dates = [ |
6a488035 TO |
547 | 'join_date', |
548 | 'start_date', | |
549 | 'end_date', | |
be2fb01f | 550 | ]; |
6a488035 TO |
551 | |
552 | foreach ($dates as $d) { | |
553 | if (isset($formatted[$d]) && | |
554 | !CRM_Utils_System::isNull($formatted[$d]) | |
555 | ) { | |
556 | $formatted[$d] = CRM_Utils_Date::isoToMysql($formatted[$d]); | |
557 | } | |
558 | elseif (isset($calcDates[$d])) { | |
559 | $formatted[$d] = CRM_Utils_Date::isoToMysql($calcDates[$d]); | |
560 | } | |
561 | } | |
562 | } | |
77b97be7 | 563 | |
3c15495c | 564 | /** |
565 | * @deprecated - this function formats params according to v2 standards but | |
566 | * need to be sure about the impact of not calling it so retaining on the import class | |
567 | * take the input parameter list as specified in the data model and | |
568 | * convert it into the same format that we use in QF and BAO object | |
569 | * | |
b2363ea8 TO |
570 | * @param array $params |
571 | * Associative array of property name/value. | |
3c15495c | 572 | * pairs to insert in new contact. |
b2363ea8 TO |
573 | * @param array $values |
574 | * The reformatted properties that we can use internally. | |
3c15495c | 575 | * |
77b97be7 | 576 | * @param array|bool $create Is the formatted Values array going to |
3c15495c | 577 | * be used for CRM_Member_BAO_Membership:create() |
578 | * | |
77b97be7 | 579 | * @throws Exception |
3c15495c | 580 | * @return array|error |
3c15495c | 581 | */ |
00be9182 | 582 | public function membership_format_params($params, &$values, $create = FALSE) { |
3c15495c | 583 | require_once 'api/v3/utils.php'; |
584 | $fields = CRM_Member_DAO_Membership::fields(); | |
585 | _civicrm_api3_store_values($fields, $params, $values); | |
586 | ||
481a74f4 | 587 | $customFields = CRM_Core_BAO_CustomField::getFields('Membership'); |
3c15495c | 588 | |
589 | foreach ($params as $key => $value) { | |
3c15495c | 590 | |
3c15495c | 591 | switch ($key) { |
209cedd9 | 592 | case 'contact_id': |
3c15495c | 593 | if (!CRM_Utils_Rule::integer($value)) { |
f719e41c | 594 | throw new Exception("contact_id not valid: $value"); |
3c15495c | 595 | } |
353ffa53 | 596 | $dao = new CRM_Core_DAO(); |
be2fb01f | 597 | $qParams = []; |
353ffa53 | 598 | $svq = $dao->singleValueQuery("SELECT id FROM civicrm_contact WHERE id = $value", |
3c15495c | 599 | $qParams |
600 | ); | |
601 | if (!$svq) { | |
f719e41c | 602 | throw new Exception("Invalid Contact ID: There is no contact record with contact_id = $value."); |
3c15495c | 603 | } |
209cedd9 | 604 | $values[$key] = $value; |
3c15495c | 605 | break; |
606 | ||
3c15495c | 607 | default: |
608 | break; | |
609 | } | |
610 | } | |
611 | ||
3c15495c | 612 | return NULL; |
613 | } | |
96025800 | 614 | |
d8844db5 EM |
615 | /** |
616 | * Set field metadata. | |
617 | */ | |
618 | protected function setFieldMetadata(): void { | |
619 | if (empty($this->importableFieldsMetadata)) { | |
209cedd9 | 620 | $metadata = CRM_Member_BAO_Membership::importableFields($this->getContactType(), FALSE); |
d8844db5 | 621 | |
209cedd9 | 622 | foreach ($metadata as $name => $field) { |
d8844db5 EM |
623 | // @todo - we don't really need to do all this.... fieldMetadata is just fine to use as is. |
624 | $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT); | |
625 | $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//'); | |
626 | $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//'); | |
627 | $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']); | |
628 | } | |
629 | // We are consolidating on `importableFieldsMetadata` - but both still used. | |
630 | $this->importableFieldsMetadata = $this->fieldMetadata = $metadata; | |
631 | } | |
632 | } | |
633 | ||
22f90136 EM |
634 | /** |
635 | * Get the metadata field for which importable fields does not key the actual field name. | |
636 | * | |
637 | * @return string[] | |
638 | */ | |
639 | protected function getOddlyMappedMetadataFields(): array { | |
640 | $uniqueNames = ['membership_id', 'membership_contact_id']; | |
641 | $fields = []; | |
642 | foreach ($uniqueNames as $name) { | |
643 | $fields[$this->importableFieldsMetadata[$name]['name']] = $name; | |
644 | } | |
645 | // Include the parent fields as they could be present if required for matching ...in theory. | |
646 | return array_merge($fields, parent::getOddlyMappedMetadataFields()); | |
647 | } | |
648 | ||
6a488035 | 649 | } |