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 | ||
18 | /** | |
74ab7ba8 | 19 | * Class to parse contribution csv files. |
6a488035 | 20 | */ |
8dc9763a | 21 | class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { |
6a488035 TO |
22 | |
23 | protected $_mapperKeys; | |
24 | ||
25 | private $_contactIdIndex; | |
6a488035 TO |
26 | |
27 | protected $_mapperSoftCredit; | |
28 | //protected $_mapperPhoneType; | |
29 | ||
30 | /** | |
ceb10dc7 | 31 | * Array of successfully imported contribution id's |
6a488035 | 32 | * |
1330f57a | 33 | * @var array |
6a488035 TO |
34 | */ |
35 | protected $_newContributions; | |
36 | ||
37 | /** | |
74ab7ba8 EM |
38 | * Class constructor. |
39 | * | |
40 | * @param $mapperKeys | |
0a2d898e | 41 | * @param array $mapperSoftCredit |
74ab7ba8 | 42 | * @param null $mapperPhoneType |
0a2d898e | 43 | * @param array $mapperSoftCreditType |
6a488035 | 44 | */ |
c2d1c1c2 | 45 | public function __construct(&$mapperKeys = [], $mapperSoftCredit = [], $mapperPhoneType = NULL, $mapperSoftCreditType = []) { |
6a488035 TO |
46 | parent::__construct(); |
47 | $this->_mapperKeys = &$mapperKeys; | |
48 | $this->_mapperSoftCredit = &$mapperSoftCredit; | |
1221efe9 | 49 | $this->_mapperSoftCreditType = &$mapperSoftCreditType; |
6a488035 TO |
50 | } |
51 | ||
8dc9763a EM |
52 | /** |
53 | * Contribution-specific result codes | |
54 | * @see CRM_Import_Parser result code constants | |
55 | */ | |
56 | const SOFT_CREDIT = 512, SOFT_CREDIT_ERROR = 1024, PLEDGE_PAYMENT = 2048, PLEDGE_PAYMENT_ERROR = 4096; | |
57 | ||
58 | /** | |
59 | * @var string | |
60 | */ | |
61 | protected $_fileName; | |
62 | ||
63 | /** | |
64 | * Imported file size | |
65 | * @var int | |
66 | */ | |
67 | protected $_fileSize; | |
68 | ||
69 | /** | |
70 | * Separator being used | |
71 | * @var string | |
72 | */ | |
73 | protected $_separator; | |
74 | ||
75 | /** | |
76 | * Total number of lines in file | |
77 | * @var int | |
78 | */ | |
79 | protected $_lineCount; | |
80 | ||
81 | /** | |
82 | * Running total number of valid soft credit rows | |
83 | * @var int | |
84 | */ | |
85 | protected $_validSoftCreditRowCount; | |
86 | ||
87 | /** | |
88 | * Running total number of invalid soft credit rows | |
89 | * @var int | |
90 | */ | |
91 | protected $_invalidSoftCreditRowCount; | |
92 | ||
93 | /** | |
94 | * Running total number of valid pledge payment rows | |
95 | * @var int | |
96 | */ | |
97 | protected $_validPledgePaymentRowCount; | |
98 | ||
99 | /** | |
100 | * Running total number of invalid pledge payment rows | |
101 | * @var int | |
102 | */ | |
103 | protected $_invalidPledgePaymentRowCount; | |
104 | ||
105 | /** | |
106 | * Array of pledge payment error lines, bounded by MAX_ERROR | |
107 | * @var array | |
108 | */ | |
109 | protected $_pledgePaymentErrors; | |
110 | ||
111 | /** | |
112 | * Array of pledge payment error lines, bounded by MAX_ERROR | |
113 | * @var array | |
114 | */ | |
115 | protected $_softCreditErrors; | |
116 | ||
117 | /** | |
118 | * Filename of pledge payment error data | |
119 | * | |
120 | * @var string | |
121 | */ | |
122 | protected $_pledgePaymentErrorsFileName; | |
123 | ||
124 | /** | |
125 | * Filename of soft credit error data | |
126 | * | |
127 | * @var string | |
128 | */ | |
129 | protected $_softCreditErrorsFileName; | |
130 | ||
131 | /** | |
132 | * Whether the file has a column header or not | |
133 | * | |
134 | * @var bool | |
135 | */ | |
136 | protected $_haveColumnHeader; | |
137 | ||
138 | /** | |
139 | * @param string $fileName | |
140 | * @param string $separator | |
141 | * @param $mapper | |
142 | * @param bool $skipColumnHeader | |
143 | * @param int $mode | |
144 | * @param int $contactType | |
145 | * @param int $onDuplicate | |
146 | * @param int $statusID | |
147 | * @param int $totalRowCount | |
148 | * | |
149 | * @return mixed | |
150 | * @throws Exception | |
151 | */ | |
152 | public function run( | |
153 | $fileName, | |
154 | $separator, | |
6d283ebd | 155 | $mapper, |
8dc9763a EM |
156 | $skipColumnHeader = FALSE, |
157 | $mode = self::MODE_PREVIEW, | |
158 | $contactType = self::CONTACT_INDIVIDUAL, | |
159 | $onDuplicate = self::DUPLICATE_SKIP, | |
160 | $statusID = NULL, | |
161 | $totalRowCount = NULL | |
162 | ) { | |
163 | if (!is_array($fileName)) { | |
164 | throw new CRM_Core_Exception('Unable to determine import file'); | |
165 | } | |
166 | $fileName = $fileName['name']; | |
167 | ||
168 | switch ($contactType) { | |
169 | case self::CONTACT_INDIVIDUAL: | |
170 | $this->_contactType = 'Individual'; | |
171 | break; | |
172 | ||
173 | case self::CONTACT_HOUSEHOLD: | |
174 | $this->_contactType = 'Household'; | |
175 | break; | |
176 | ||
177 | case self::CONTACT_ORGANIZATION: | |
178 | $this->_contactType = 'Organization'; | |
179 | } | |
180 | ||
181 | $this->init(); | |
182 | ||
183 | $this->_haveColumnHeader = $skipColumnHeader; | |
184 | ||
185 | $this->_separator = $separator; | |
186 | ||
187 | $fd = fopen($fileName, "r"); | |
188 | if (!$fd) { | |
189 | return FALSE; | |
190 | } | |
191 | ||
06ef1cdc | 192 | $this->_lineCount = $this->_validSoftCreditRowCount = $this->_validPledgePaymentRowCount = 0; |
8dc9763a | 193 | $this->_invalidRowCount = $this->_validCount = $this->_invalidSoftCreditRowCount = $this->_invalidPledgePaymentRowCount = 0; |
da8d3d49 | 194 | $this->_totalCount = 0; |
8dc9763a EM |
195 | |
196 | $this->_errors = []; | |
197 | $this->_warnings = []; | |
8dc9763a EM |
198 | $this->_pledgePaymentErrors = []; |
199 | $this->_softCreditErrors = []; | |
200 | if ($statusID) { | |
201 | $this->progressImport($statusID); | |
202 | $startTimestamp = $currTimestamp = $prevTimestamp = time(); | |
203 | } | |
204 | ||
205 | $this->_fileSize = number_format(filesize($fileName) / 1024.0, 2); | |
206 | ||
207 | if ($mode == self::MODE_MAPFIELD) { | |
208 | $this->_rows = []; | |
209 | } | |
210 | else { | |
211 | $this->_activeFieldCount = count($this->_activeFields); | |
212 | } | |
213 | ||
214 | while (!feof($fd)) { | |
215 | $this->_lineCount++; | |
216 | ||
217 | $values = fgetcsv($fd, 8192, $separator); | |
218 | if (!$values) { | |
219 | continue; | |
220 | } | |
221 | ||
222 | self::encloseScrub($values); | |
223 | ||
224 | // skip column header if we're not in mapfield mode | |
225 | if ($mode != self::MODE_MAPFIELD && $skipColumnHeader) { | |
226 | $skipColumnHeader = FALSE; | |
227 | continue; | |
228 | } | |
229 | ||
230 | /* trim whitespace around the values */ | |
231 | ||
232 | $empty = TRUE; | |
233 | foreach ($values as $k => $v) { | |
234 | $values[$k] = trim($v, " \t\r\n"); | |
235 | } | |
236 | ||
237 | if (CRM_Utils_System::isNull($values)) { | |
238 | continue; | |
239 | } | |
240 | ||
241 | $this->_totalCount++; | |
242 | ||
243 | if ($mode == self::MODE_MAPFIELD) { | |
4ad623fc | 244 | $returnCode = CRM_Import_Parser::VALID; |
8dc9763a | 245 | } |
5f97768e EM |
246 | // Note that import summary appears to be unused |
247 | elseif ($mode == self::MODE_PREVIEW || $mode == self::MODE_SUMMARY) { | |
8dc9763a EM |
248 | $returnCode = $this->summary($values); |
249 | } | |
250 | elseif ($mode == self::MODE_IMPORT) { | |
251 | $returnCode = $this->import($onDuplicate, $values); | |
252 | if ($statusID && (($this->_lineCount % 50) == 0)) { | |
253 | $prevTimestamp = $this->progressImport($statusID, FALSE, $startTimestamp, $prevTimestamp, $totalRowCount); | |
254 | } | |
255 | } | |
256 | else { | |
257 | $returnCode = self::ERROR; | |
258 | } | |
259 | ||
260 | // note that a line could be valid but still produce a warning | |
261 | if ($returnCode == self::VALID) { | |
262 | $this->_validCount++; | |
263 | if ($mode == self::MODE_MAPFIELD) { | |
264 | $this->_rows[] = $values; | |
265 | $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); | |
266 | } | |
267 | } | |
268 | ||
269 | if ($returnCode == self::SOFT_CREDIT) { | |
270 | $this->_validSoftCreditRowCount++; | |
271 | $this->_validCount++; | |
272 | if ($mode == self::MODE_MAPFIELD) { | |
273 | $this->_rows[] = $values; | |
274 | $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); | |
275 | } | |
276 | } | |
277 | ||
278 | if ($returnCode == self::PLEDGE_PAYMENT) { | |
279 | $this->_validPledgePaymentRowCount++; | |
280 | $this->_validCount++; | |
281 | if ($mode == self::MODE_MAPFIELD) { | |
282 | $this->_rows[] = $values; | |
283 | $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); | |
284 | } | |
285 | } | |
286 | ||
8dc9763a EM |
287 | if ($returnCode == self::ERROR) { |
288 | $this->_invalidRowCount++; | |
289 | $recordNumber = $this->_lineCount; | |
290 | if ($this->_haveColumnHeader) { | |
291 | $recordNumber--; | |
292 | } | |
293 | array_unshift($values, $recordNumber); | |
294 | $this->_errors[] = $values; | |
295 | } | |
296 | ||
297 | if ($returnCode == self::PLEDGE_PAYMENT_ERROR) { | |
298 | $this->_invalidPledgePaymentRowCount++; | |
299 | $recordNumber = $this->_lineCount; | |
300 | if ($this->_haveColumnHeader) { | |
301 | $recordNumber--; | |
302 | } | |
303 | array_unshift($values, $recordNumber); | |
304 | $this->_pledgePaymentErrors[] = $values; | |
305 | } | |
306 | ||
307 | if ($returnCode == self::SOFT_CREDIT_ERROR) { | |
308 | $this->_invalidSoftCreditRowCount++; | |
309 | $recordNumber = $this->_lineCount; | |
310 | if ($this->_haveColumnHeader) { | |
311 | $recordNumber--; | |
312 | } | |
313 | array_unshift($values, $recordNumber); | |
314 | $this->_softCreditErrors[] = $values; | |
315 | } | |
316 | ||
8dc9763a | 317 | if ($returnCode == self::DUPLICATE) { |
8dc9763a EM |
318 | $this->_duplicateCount++; |
319 | $recordNumber = $this->_lineCount; | |
320 | if ($this->_haveColumnHeader) { | |
321 | $recordNumber--; | |
322 | } | |
323 | array_unshift($values, $recordNumber); | |
324 | $this->_duplicates[] = $values; | |
325 | if ($onDuplicate != self::DUPLICATE_SKIP) { | |
326 | $this->_validCount++; | |
327 | } | |
328 | } | |
329 | ||
8dc9763a EM |
330 | // if we are done processing the maxNumber of lines, break |
331 | if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) { | |
332 | break; | |
333 | } | |
334 | } | |
335 | ||
336 | fclose($fd); | |
337 | ||
338 | if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) { | |
339 | $customHeaders = $mapper; | |
340 | ||
341 | $customfields = CRM_Core_BAO_CustomField::getFields('Contribution'); | |
342 | foreach ($customHeaders as $key => $value) { | |
343 | if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) { | |
344 | $customHeaders[$key] = $customfields[$id][0]; | |
345 | } | |
346 | } | |
347 | if ($this->_invalidRowCount) { | |
348 | // removed view url for invlaid contacts | |
349 | $headers = array_merge([ | |
350 | ts('Line Number'), | |
351 | ts('Reason'), | |
352 | ], $customHeaders); | |
353 | $this->_errorFileName = self::errorFileName(self::ERROR); | |
354 | self::exportCSV($this->_errorFileName, $headers, $this->_errors); | |
355 | } | |
356 | ||
357 | if ($this->_invalidPledgePaymentRowCount) { | |
358 | // removed view url for invlaid contacts | |
359 | $headers = array_merge([ | |
360 | ts('Line Number'), | |
361 | ts('Reason'), | |
362 | ], $customHeaders); | |
363 | $this->_pledgePaymentErrorsFileName = self::errorFileName(self::PLEDGE_PAYMENT_ERROR); | |
364 | self::exportCSV($this->_pledgePaymentErrorsFileName, $headers, $this->_pledgePaymentErrors); | |
365 | } | |
366 | ||
367 | if ($this->_invalidSoftCreditRowCount) { | |
368 | // removed view url for invlaid contacts | |
369 | $headers = array_merge([ | |
370 | ts('Line Number'), | |
371 | ts('Reason'), | |
372 | ], $customHeaders); | |
373 | $this->_softCreditErrorsFileName = self::errorFileName(self::SOFT_CREDIT_ERROR); | |
374 | self::exportCSV($this->_softCreditErrorsFileName, $headers, $this->_softCreditErrors); | |
375 | } | |
376 | ||
8dc9763a EM |
377 | if ($this->_duplicateCount) { |
378 | $headers = array_merge([ | |
379 | ts('Line Number'), | |
380 | ts('View Contribution URL'), | |
381 | ], $customHeaders); | |
382 | ||
383 | $this->_duplicateFileName = self::errorFileName(self::DUPLICATE); | |
384 | self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates); | |
385 | } | |
386 | } | |
8dc9763a EM |
387 | } |
388 | ||
389 | /** | |
390 | * Given a list of the importable field keys that the user has selected | |
391 | * set the active fields array to this list | |
392 | * | |
393 | * @param array $fieldKeys mapped array of values | |
394 | */ | |
395 | public function setActiveFields($fieldKeys) { | |
396 | $this->_activeFieldCount = count($fieldKeys); | |
397 | foreach ($fieldKeys as $key) { | |
398 | if (empty($this->_fields[$key])) { | |
399 | $this->_activeFields[] = new CRM_Contribute_Import_Field('', ts('- do not import -')); | |
400 | } | |
401 | else { | |
402 | $this->_activeFields[] = clone($this->_fields[$key]); | |
403 | } | |
404 | } | |
405 | } | |
406 | ||
407 | /** | |
408 | * Store the soft credit field information. | |
409 | * | |
410 | * This was perhaps done this way on the believe that a lot of code pain | |
411 | * was worth it to avoid negligible-cost array iterations. Perhaps we could prioritise | |
412 | * readability & maintainability next since we can just work with functions to retrieve | |
413 | * data from the metadata. | |
414 | * | |
415 | * @param array $elements | |
416 | */ | |
417 | public function setActiveFieldSoftCredit($elements) { | |
418 | foreach ((array) $elements as $i => $element) { | |
419 | $this->_activeFields[$i]->_softCreditField = $element; | |
420 | } | |
421 | } | |
422 | ||
423 | /** | |
424 | * Store the soft credit field type information. | |
425 | * | |
426 | * This was perhaps done this way on the believe that a lot of code pain | |
427 | * was worth it to avoid negligible-cost array iterations. Perhaps we could prioritise | |
428 | * readability & maintainability next since we can just work with functions to retrieve | |
429 | * data from the metadata. | |
430 | * | |
431 | * @param array $elements | |
432 | */ | |
433 | public function setActiveFieldSoftCreditType($elements) { | |
434 | foreach ((array) $elements as $i => $element) { | |
435 | $this->_activeFields[$i]->_softCreditType = $element; | |
436 | } | |
437 | } | |
438 | ||
439 | /** | |
440 | * Format the field values for input to the api. | |
441 | * | |
442 | * @return array | |
443 | * (reference ) associative array of name/value pairs | |
444 | */ | |
445 | public function &getActiveFieldParams() { | |
446 | $params = []; | |
447 | for ($i = 0; $i < $this->_activeFieldCount; $i++) { | |
448 | if (isset($this->_activeFields[$i]->_value)) { | |
449 | if (isset($this->_activeFields[$i]->_softCreditField)) { | |
450 | if (!isset($params[$this->_activeFields[$i]->_name])) { | |
451 | $params[$this->_activeFields[$i]->_name] = []; | |
452 | } | |
453 | $params[$this->_activeFields[$i]->_name][$i][$this->_activeFields[$i]->_softCreditField] = $this->_activeFields[$i]->_value; | |
454 | if (isset($this->_activeFields[$i]->_softCreditType)) { | |
455 | $params[$this->_activeFields[$i]->_name][$i]['soft_credit_type_id'] = $this->_activeFields[$i]->_softCreditType; | |
456 | } | |
457 | } | |
458 | ||
459 | if (!isset($params[$this->_activeFields[$i]->_name])) { | |
460 | if (!isset($this->_activeFields[$i]->_softCreditField)) { | |
461 | $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value; | |
462 | } | |
463 | } | |
464 | } | |
465 | } | |
466 | return $params; | |
467 | } | |
468 | ||
469 | /** | |
470 | * @param string $name | |
471 | * @param $title | |
472 | * @param int $type | |
473 | * @param string $headerPattern | |
474 | * @param string $dataPattern | |
475 | */ | |
476 | public function addField($name, $title, $type = CRM_Utils_Type::T_INT, $headerPattern = '//', $dataPattern = '//') { | |
477 | if (empty($name)) { | |
478 | $this->_fields['doNotImport'] = new CRM_Contribute_Import_Field($name, $title, $type, $headerPattern, $dataPattern); | |
479 | } | |
480 | else { | |
481 | $tempField = CRM_Contact_BAO_Contact::importableFields('All', NULL); | |
482 | if (!array_key_exists($name, $tempField)) { | |
483 | $this->_fields[$name] = new CRM_Contribute_Import_Field($name, $title, $type, $headerPattern, $dataPattern); | |
484 | } | |
485 | else { | |
486 | $this->_fields[$name] = new CRM_Contact_Import_Field($name, $title, $type, $headerPattern, $dataPattern, | |
487 | CRM_Utils_Array::value('hasLocationType', $tempField[$name]) | |
488 | ); | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | /** | |
494 | * Store parser values. | |
495 | * | |
496 | * @param CRM_Core_Session $store | |
497 | * | |
498 | * @param int $mode | |
499 | */ | |
500 | public function set($store, $mode = self::MODE_SUMMARY) { | |
501 | $store->set('fileSize', $this->_fileSize); | |
502 | $store->set('lineCount', $this->_lineCount); | |
503 | $store->set('separator', $this->_separator); | |
504 | $store->set('fields', $this->getSelectValues()); | |
8dc9763a EM |
505 | |
506 | $store->set('headerPatterns', $this->getHeaderPatterns()); | |
507 | $store->set('dataPatterns', $this->getDataPatterns()); | |
508 | $store->set('columnCount', $this->_activeFieldCount); | |
509 | ||
510 | $store->set('totalRowCount', $this->_totalCount); | |
511 | $store->set('validRowCount', $this->_validCount); | |
512 | $store->set('invalidRowCount', $this->_invalidRowCount); | |
513 | $store->set('invalidSoftCreditRowCount', $this->_invalidSoftCreditRowCount); | |
514 | $store->set('validSoftCreditRowCount', $this->_validSoftCreditRowCount); | |
515 | $store->set('invalidPledgePaymentRowCount', $this->_invalidPledgePaymentRowCount); | |
516 | $store->set('validPledgePaymentRowCount', $this->_validPledgePaymentRowCount); | |
8dc9763a EM |
517 | |
518 | switch ($this->_contactType) { | |
519 | case 'Individual': | |
520 | $store->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL); | |
521 | break; | |
522 | ||
523 | case 'Household': | |
524 | $store->set('contactType', CRM_Import_Parser::CONTACT_HOUSEHOLD); | |
525 | break; | |
526 | ||
527 | case 'Organization': | |
528 | $store->set('contactType', CRM_Import_Parser::CONTACT_ORGANIZATION); | |
529 | } | |
530 | ||
531 | if ($this->_invalidRowCount) { | |
532 | $store->set('errorsFileName', $this->_errorFileName); | |
533 | } | |
8dc9763a EM |
534 | if (isset($this->_rows) && !empty($this->_rows)) { |
535 | $store->set('dataValues', $this->_rows); | |
536 | } | |
537 | ||
538 | if ($this->_invalidPledgePaymentRowCount) { | |
539 | $store->set('pledgePaymentErrorsFileName', $this->_pledgePaymentErrorsFileName); | |
540 | } | |
541 | ||
542 | if ($this->_invalidSoftCreditRowCount) { | |
543 | $store->set('softCreditErrorsFileName', $this->_softCreditErrorsFileName); | |
544 | } | |
545 | ||
546 | if ($mode == self::MODE_IMPORT) { | |
547 | $store->set('duplicateRowCount', $this->_duplicateCount); | |
548 | if ($this->_duplicateCount) { | |
549 | $store->set('duplicatesFileName', $this->_duplicateFileName); | |
550 | } | |
551 | } | |
552 | } | |
553 | ||
554 | /** | |
555 | * Export data to a CSV file. | |
556 | * | |
557 | * @param string $fileName | |
558 | * @param array $header | |
559 | * @param array $data | |
560 | */ | |
561 | public static function exportCSV($fileName, $header, $data) { | |
562 | $output = []; | |
563 | $fd = fopen($fileName, 'w'); | |
564 | ||
565 | foreach ($header as $key => $value) { | |
566 | $header[$key] = "\"$value\""; | |
567 | } | |
568 | $config = CRM_Core_Config::singleton(); | |
569 | $output[] = implode($config->fieldSeparator, $header); | |
570 | ||
571 | foreach ($data as $datum) { | |
572 | foreach ($datum as $key => $value) { | |
573 | if (isset($value[0]) && is_array($value)) { | |
574 | foreach ($value[0] as $k1 => $v1) { | |
575 | if ($k1 == 'location_type_id') { | |
576 | continue; | |
577 | } | |
578 | $datum[$k1] = $v1; | |
579 | } | |
580 | } | |
581 | else { | |
582 | $datum[$key] = "\"$value\""; | |
583 | } | |
584 | } | |
585 | $output[] = implode($config->fieldSeparator, $datum); | |
586 | } | |
587 | fwrite($fd, implode("\n", $output)); | |
588 | fclose($fd); | |
589 | } | |
590 | ||
591 | /** | |
592 | * Determines the file extension based on error code. | |
593 | * | |
594 | * @param int $type | |
595 | * Error code constant. | |
596 | * | |
597 | * @return string | |
598 | */ | |
599 | public static function errorFileName($type) { | |
600 | $fileName = NULL; | |
601 | if (empty($type)) { | |
602 | return $fileName; | |
603 | } | |
604 | ||
605 | $config = CRM_Core_Config::singleton(); | |
606 | $fileName = $config->uploadDir . "sqlImport"; | |
607 | ||
608 | switch ($type) { | |
609 | case self::SOFT_CREDIT_ERROR: | |
610 | $fileName .= '.softCreditErrors'; | |
611 | break; | |
612 | ||
613 | case self::PLEDGE_PAYMENT_ERROR: | |
614 | $fileName .= '.pledgePaymentErrors'; | |
615 | break; | |
616 | ||
617 | default: | |
618 | $fileName = parent::errorFileName($type); | |
619 | break; | |
620 | } | |
621 | ||
622 | return $fileName; | |
623 | } | |
624 | ||
625 | /** | |
626 | * Determines the file name based on error code. | |
627 | * | |
628 | * @param int $type | |
629 | * Error code constant. | |
630 | * | |
631 | * @return string | |
632 | */ | |
633 | public static function saveFileName($type) { | |
634 | $fileName = NULL; | |
635 | if (empty($type)) { | |
636 | return $fileName; | |
637 | } | |
638 | ||
639 | switch ($type) { | |
640 | case self::SOFT_CREDIT_ERROR: | |
641 | $fileName = 'Import_Soft_Credit_Errors.csv'; | |
642 | break; | |
643 | ||
644 | case self::PLEDGE_PAYMENT_ERROR: | |
645 | $fileName = 'Import_Pledge_Payment_Errors.csv'; | |
646 | break; | |
647 | ||
648 | default: | |
649 | $fileName = parent::saveFileName($type); | |
650 | break; | |
651 | } | |
652 | ||
653 | return $fileName; | |
654 | } | |
655 | ||
6a488035 | 656 | /** |
100fef9d | 657 | * The initializer code, called before the processing |
6a488035 | 658 | */ |
00be9182 | 659 | public function init() { |
73edfc10 EM |
660 | $this->setFieldMetadata(); |
661 | foreach ($this->getImportableFieldsMetadata() as $name => $field) { | |
6a488035 TO |
662 | $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']); |
663 | } | |
664 | ||
be2fb01f | 665 | $this->_newContributions = []; |
6a488035 TO |
666 | |
667 | $this->setActiveFields($this->_mapperKeys); | |
668 | $this->setActiveFieldSoftCredit($this->_mapperSoftCredit); | |
1221efe9 | 669 | $this->setActiveFieldSoftCreditType($this->_mapperSoftCreditType); |
6a488035 TO |
670 | |
671 | // FIXME: we should do this in one place together with Form/MapField.php | |
672 | $this->_contactIdIndex = -1; | |
6a488035 TO |
673 | |
674 | $index = 0; | |
675 | foreach ($this->_mapperKeys as $key) { | |
676 | switch ($key) { | |
677 | case 'contribution_contact_id': | |
678 | $this->_contactIdIndex = $index; | |
679 | break; | |
680 | ||
6a488035 TO |
681 | } |
682 | $index++; | |
683 | } | |
684 | } | |
685 | ||
73edfc10 EM |
686 | /** |
687 | * Set field metadata. | |
688 | */ | |
689 | protected function setFieldMetadata() { | |
690 | if (empty($this->importableFieldsMetadata)) { | |
691 | $fields = CRM_Contribute_BAO_Contribution::importableFields($this->_contactType, FALSE); | |
692 | ||
693 | $fields = array_merge($fields, | |
694 | [ | |
695 | 'soft_credit' => [ | |
696 | 'title' => ts('Soft Credit'), | |
697 | 'softCredit' => TRUE, | |
698 | 'headerPattern' => '/Soft Credit/i', | |
699 | ], | |
700 | ] | |
701 | ); | |
702 | ||
703 | // add pledge fields only if its is enabled | |
704 | if (CRM_Core_Permission::access('CiviPledge')) { | |
705 | $pledgeFields = [ | |
706 | 'pledge_payment' => [ | |
707 | 'title' => ts('Pledge Payment'), | |
708 | 'headerPattern' => '/Pledge Payment/i', | |
709 | ], | |
710 | 'pledge_id' => [ | |
711 | 'title' => ts('Pledge ID'), | |
712 | 'headerPattern' => '/Pledge ID/i', | |
713 | ], | |
714 | ]; | |
715 | ||
716 | $fields = array_merge($fields, $pledgeFields); | |
717 | } | |
718 | foreach ($fields as $name => $field) { | |
719 | $fields[$name] = array_merge([ | |
720 | 'type' => CRM_Utils_Type::T_INT, | |
721 | 'dataPattern' => '//', | |
722 | 'headerPattern' => '//', | |
723 | ], $field); | |
724 | } | |
725 | $this->importableFieldsMetadata = $fields; | |
726 | } | |
727 | } | |
728 | ||
6a488035 | 729 | /** |
fe482240 | 730 | * Handle the values in summary mode. |
6a488035 | 731 | * |
014c4014 TO |
732 | * @param array $values |
733 | * The array of values belonging to this line. | |
6a488035 | 734 | * |
5f97768e EM |
735 | * @return int |
736 | * CRM_Import_Parser::VALID or CRM_Import_Parser::ERROR | |
6a488035 | 737 | */ |
00be9182 | 738 | public function summary(&$values) { |
daff3687 | 739 | $this->setActiveFieldValues($values); |
6a488035 | 740 | |
daff3687 | 741 | $params = $this->getActiveFieldParams(); |
6a488035 TO |
742 | |
743 | //for date-Formats | |
341c643b | 744 | $errorMessage = implode('; ', $this->formatDateFields($params)); |
6a488035 TO |
745 | //date-Format part ends |
746 | ||
747 | $params['contact_type'] = 'Contribution'; | |
748 | ||
749 | //checking error in custom data | |
719a6fec | 750 | CRM_Contact_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage); |
6a488035 TO |
751 | |
752 | if ($errorMessage) { | |
753 | $tempMsg = "Invalid value for field(s) : $errorMessage"; | |
754 | array_unshift($values, $tempMsg); | |
755 | $errorMessage = NULL; | |
a05662ef | 756 | return CRM_Import_Parser::ERROR; |
6a488035 TO |
757 | } |
758 | ||
a05662ef | 759 | return CRM_Import_Parser::VALID; |
6a488035 TO |
760 | } |
761 | ||
762 | /** | |
fe482240 | 763 | * Handle the values in import mode. |
6a488035 | 764 | * |
014c4014 TO |
765 | * @param int $onDuplicate |
766 | * The code for what action to take on duplicates. | |
767 | * @param array $values | |
768 | * The array of values belonging to this line. | |
6a488035 | 769 | * |
5f97768e EM |
770 | * @return int |
771 | * the result of this processing - one of | |
772 | * - CRM_Import_Parser::VALID | |
773 | * - CRM_Import_Parser::ERROR | |
774 | * - CRM_Import_Parser::SOFT_CREDIT_ERROR | |
775 | * - CRM_Import_Parser::PLEDGE_PAYMENT_ERROR | |
776 | * - CRM_Import_Parser::DUPLICATE | |
777 | * - CRM_Import_Parser::SOFT_CREDIT (successful creation) | |
778 | * - CRM_Import_Parser::PLEDGE_PAYMENT (successful creation) | |
6a488035 | 779 | */ |
00be9182 | 780 | public function import($onDuplicate, &$values) { |
6a488035 TO |
781 | // first make sure this is a valid line |
782 | $response = $this->summary($values); | |
a05662ef | 783 | if ($response != CRM_Import_Parser::VALID) { |
5f97768e | 784 | return CRM_Import_Parser::ERROR; |
6a488035 TO |
785 | } |
786 | ||
787 | $params = &$this->getActiveFieldParams(); | |
9d8db541 | 788 | $formatted = ['version' => 3, 'skipRecentView' => TRUE, 'skipCleanMoney' => FALSE]; |
6a488035 | 789 | |
c2e1f9ef | 790 | //CRM-10994 |
791 | if (isset($params['total_amount']) && $params['total_amount'] == 0) { | |
1ba834a8 | 792 | $params['total_amount'] = '0.00'; |
c2e1f9ef | 793 | } |
fed96c11 | 794 | $this->formatInput($params, $formatted); |
6a488035 TO |
795 | |
796 | static $indieFields = NULL; | |
797 | if ($indieFields == NULL) { | |
798 | $tempIndieFields = CRM_Contribute_DAO_Contribution::import(); | |
799 | $indieFields = $tempIndieFields; | |
800 | } | |
801 | ||
be2fb01f | 802 | $paramValues = []; |
6a488035 TO |
803 | foreach ($params as $key => $field) { |
804 | if ($field == NULL || $field === '') { | |
805 | continue; | |
806 | } | |
807 | $paramValues[$key] = $field; | |
808 | } | |
809 | ||
810 | //import contribution record according to select contact type | |
a05662ef | 811 | if ($onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP && |
8cc574cf | 812 | (!empty($paramValues['contribution_contact_id']) || !empty($paramValues['external_identifier'])) |
6a488035 TO |
813 | ) { |
814 | $paramValues['contact_type'] = $this->_contactType; | |
815 | } | |
a05662ef | 816 | elseif ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE && |
1221efe9 | 817 | (!empty($paramValues['contribution_id']) || !empty($values['trxn_id']) || !empty($paramValues['invoice_id'])) |
6a488035 TO |
818 | ) { |
819 | $paramValues['contact_type'] = $this->_contactType; | |
820 | } | |
821 | elseif (!empty($params['soft_credit'])) { | |
822 | $paramValues['contact_type'] = $this->_contactType; | |
823 | } | |
a7488080 | 824 | elseif (!empty($paramValues['pledge_payment'])) { |
6a488035 TO |
825 | $paramValues['contact_type'] = $this->_contactType; |
826 | } | |
827 | ||
828 | //need to pass $onDuplicate to check import mode. | |
a7488080 | 829 | if (!empty($paramValues['pledge_payment'])) { |
6a488035 TO |
830 | $paramValues['onDuplicate'] = $onDuplicate; |
831 | } | |
4fc2ce46 | 832 | $formatError = $this->deprecatedFormatParams($paramValues, $formatted, TRUE, $onDuplicate); |
6a488035 TO |
833 | |
834 | if ($formatError) { | |
835 | array_unshift($values, $formatError['error_message']); | |
836 | if (CRM_Utils_Array::value('error_data', $formatError) == 'soft_credit') { | |
8dc9763a | 837 | return self::SOFT_CREDIT_ERROR; |
6a488035 | 838 | } |
69f296a4 | 839 | if (CRM_Utils_Array::value('error_data', $formatError) == 'pledge_payment') { |
8dc9763a | 840 | return self::PLEDGE_PAYMENT_ERROR; |
6a488035 | 841 | } |
a05662ef | 842 | return CRM_Import_Parser::ERROR; |
6a488035 TO |
843 | } |
844 | ||
f6fc1b15 | 845 | if ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE) { |
6a488035 | 846 | //fix for CRM-2219 - Update Contribution |
a05662ef | 847 | // onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE |
1221efe9 | 848 | if (!empty($paramValues['invoice_id']) || !empty($paramValues['trxn_id']) || !empty($paramValues['contribution_id'])) { |
be2fb01f | 849 | $dupeIds = [ |
6b409353 CW |
850 | 'id' => $paramValues['contribution_id'] ?? NULL, |
851 | 'trxn_id' => $paramValues['trxn_id'] ?? NULL, | |
852 | 'invoice_id' => $paramValues['invoice_id'] ?? NULL, | |
be2fb01f | 853 | ]; |
6a488035 TO |
854 | $ids['contribution'] = CRM_Contribute_BAO_Contribution::checkDuplicateIds($dupeIds); |
855 | ||
856 | if ($ids['contribution']) { | |
857 | $formatted['id'] = $ids['contribution']; | |
6a488035 | 858 | //process note |
a7488080 | 859 | if (!empty($paramValues['note'])) { |
be2fb01f | 860 | $noteID = []; |
6a488035 TO |
861 | $contactID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $ids['contribution'], 'contact_id'); |
862 | $daoNote = new CRM_Core_BAO_Note(); | |
863 | $daoNote->entity_table = 'civicrm_contribution'; | |
864 | $daoNote->entity_id = $ids['contribution']; | |
865 | if ($daoNote->find(TRUE)) { | |
866 | $noteID['id'] = $daoNote->id; | |
867 | } | |
868 | ||
be2fb01f | 869 | $noteParams = [ |
6a488035 TO |
870 | 'entity_table' => 'civicrm_contribution', |
871 | 'note' => $paramValues['note'], | |
872 | 'entity_id' => $ids['contribution'], | |
873 | 'contact_id' => $contactID, | |
be2fb01f | 874 | ]; |
6a488035 TO |
875 | CRM_Core_BAO_Note::add($noteParams, $noteID); |
876 | unset($formatted['note']); | |
877 | } | |
878 | ||
879 | //need to check existing soft credit contribution, CRM-3968 | |
1221efe9 | 880 | if (!empty($formatted['soft_credit'])) { |
be2fb01f | 881 | $dupeSoftCredit = [ |
1221efe9 | 882 | 'contact_id' => $formatted['soft_credit'], |
6a488035 | 883 | 'contribution_id' => $ids['contribution'], |
be2fb01f | 884 | ]; |
8ef12e64 | 885 | |
1221efe9 | 886 | //Delete all existing soft Contribution from contribution_soft table for pcp_id is_null |
91bb24a7 | 887 | $existingSoftCredit = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($dupeSoftCredit['contribution_id']); |
9b873358 TO |
888 | if (isset($existingSoftCredit['soft_credit']) && !empty($existingSoftCredit['soft_credit'])) { |
889 | foreach ($existingSoftCredit['soft_credit'] as $key => $existingSoftCreditValues) { | |
1221efe9 | 890 | if (!empty($existingSoftCreditValues['soft_credit_id'])) { |
be2fb01f | 891 | civicrm_api3('ContributionSoft', 'delete', [ |
1221efe9 | 892 | 'id' => $existingSoftCreditValues['soft_credit_id'], |
893 | 'pcp_id' => NULL, | |
be2fb01f | 894 | ]); |
1221efe9 | 895 | } |
896 | } | |
6a488035 TO |
897 | } |
898 | } | |
899 | ||
70d43afb | 900 | $formatted['id'] = $ids['contribution']; |
f6fc1b15 JM |
901 | |
902 | $newContribution = civicrm_api3('contribution', 'create', $formatted); | |
903 | $this->_newContributions[] = $newContribution['id']; | |
6a488035 TO |
904 | |
905 | //return soft valid since we need to show how soft credits were added | |
1221efe9 | 906 | if (!empty($formatted['soft_credit'])) { |
8dc9763a | 907 | return self::SOFT_CREDIT; |
6a488035 TO |
908 | } |
909 | ||
910 | // process pledge payment assoc w/ the contribution | |
672b72ea | 911 | return $this->processPledgePayments($formatted); |
6a488035 | 912 | } |
69f296a4 | 913 | $labels = [ |
914 | 'id' => 'Contribution ID', | |
915 | 'trxn_id' => 'Transaction ID', | |
916 | 'invoice_id' => 'Invoice ID', | |
917 | ]; | |
918 | foreach ($dupeIds as $k => $v) { | |
919 | if ($v) { | |
920 | $errorMsg[] = "$labels[$k] $v"; | |
6a488035 | 921 | } |
6a488035 | 922 | } |
69f296a4 | 923 | $errorMsg = implode(' AND ', $errorMsg); |
924 | array_unshift($values, 'Matching Contribution record not found for ' . $errorMsg . '. Row was skipped.'); | |
925 | return CRM_Import_Parser::ERROR; | |
6a488035 TO |
926 | } |
927 | } | |
928 | ||
929 | if ($this->_contactIdIndex < 0) { | |
6a488035 | 930 | |
56316747 | 931 | $error = $this->checkContactDuplicate($paramValues); |
6a488035 TO |
932 | |
933 | if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) { | |
934 | $matchedIDs = explode(',', $error['error_message']['params'][0]); | |
935 | if (count($matchedIDs) > 1) { | |
936 | array_unshift($values, 'Multiple matching contact records detected for this row. The contribution was not imported'); | |
a05662ef | 937 | return CRM_Import_Parser::ERROR; |
6a488035 | 938 | } |
69f296a4 | 939 | $cid = $matchedIDs[0]; |
940 | $formatted['contact_id'] = $cid; | |
941 | ||
942 | $newContribution = civicrm_api('contribution', 'create', $formatted); | |
943 | if (civicrm_error($newContribution)) { | |
944 | if (is_array($newContribution['error_message'])) { | |
945 | array_unshift($values, $newContribution['error_message']['message']); | |
946 | if ($newContribution['error_message']['params'][0]) { | |
947 | return CRM_Import_Parser::DUPLICATE; | |
6a488035 TO |
948 | } |
949 | } | |
69f296a4 | 950 | else { |
951 | array_unshift($values, $newContribution['error_message']); | |
952 | return CRM_Import_Parser::ERROR; | |
6a488035 | 953 | } |
69f296a4 | 954 | } |
6a488035 | 955 | |
69f296a4 | 956 | $this->_newContributions[] = $newContribution['id']; |
957 | $formatted['contribution_id'] = $newContribution['id']; | |
6a488035 | 958 | |
69f296a4 | 959 | //return soft valid since we need to show how soft credits were added |
960 | if (!empty($formatted['soft_credit'])) { | |
8dc9763a | 961 | return self::SOFT_CREDIT; |
6a488035 | 962 | } |
69f296a4 | 963 | |
964 | // process pledge payment assoc w/ the contribution | |
672b72ea | 965 | return $this->processPledgePayments($formatted); |
6a488035 | 966 | } |
6a488035 | 967 | |
69f296a4 | 968 | // Using new Dedupe rule. |
969 | $ruleParams = [ | |
970 | 'contact_type' => $this->_contactType, | |
971 | 'used' => 'Unsupervised', | |
972 | ]; | |
61194d45 | 973 | $fieldsArray = CRM_Dedupe_BAO_DedupeRule::dedupeRuleFields($ruleParams); |
69f296a4 | 974 | $disp = NULL; |
975 | foreach ($fieldsArray as $value) { | |
976 | if (array_key_exists(trim($value), $params)) { | |
977 | $paramValue = $params[trim($value)]; | |
978 | if (is_array($paramValue)) { | |
979 | $disp .= $params[trim($value)][0][trim($value)] . " "; | |
6a488035 TO |
980 | } |
981 | else { | |
69f296a4 | 982 | $disp .= $params[trim($value)] . " "; |
6a488035 TO |
983 | } |
984 | } | |
6a488035 | 985 | } |
69f296a4 | 986 | |
987 | if (!empty($params['external_identifier'])) { | |
988 | if ($disp) { | |
989 | $disp .= "AND {$params['external_identifier']}"; | |
6a488035 TO |
990 | } |
991 | else { | |
69f296a4 | 992 | $disp = $params['external_identifier']; |
6a488035 TO |
993 | } |
994 | } | |
995 | ||
69f296a4 | 996 | array_unshift($values, 'No matching Contact found for (' . $disp . ')'); |
997 | return CRM_Import_Parser::ERROR; | |
998 | } | |
6a488035 | 999 | |
69f296a4 | 1000 | if (!empty($paramValues['external_identifier'])) { |
1001 | $checkCid = new CRM_Contact_DAO_Contact(); | |
1002 | $checkCid->external_identifier = $paramValues['external_identifier']; | |
1003 | $checkCid->find(TRUE); | |
1004 | if ($checkCid->id != $formatted['contact_id']) { | |
1005 | array_unshift($values, 'Mismatch of External ID:' . $paramValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id']); | |
1006 | return CRM_Import_Parser::ERROR; | |
1007 | } | |
1008 | } | |
1009 | $newContribution = civicrm_api('contribution', 'create', $formatted); | |
1010 | if (civicrm_error($newContribution)) { | |
1011 | if (is_array($newContribution['error_message'])) { | |
1012 | array_unshift($values, $newContribution['error_message']['message']); | |
1013 | if ($newContribution['error_message']['params'][0]) { | |
1014 | return CRM_Import_Parser::DUPLICATE; | |
1015 | } | |
6a488035 | 1016 | } |
69f296a4 | 1017 | else { |
1018 | array_unshift($values, $newContribution['error_message']); | |
1019 | return CRM_Import_Parser::ERROR; | |
1020 | } | |
1021 | } | |
6a488035 | 1022 | |
69f296a4 | 1023 | $this->_newContributions[] = $newContribution['id']; |
1024 | $formatted['contribution_id'] = $newContribution['id']; | |
6a488035 | 1025 | |
69f296a4 | 1026 | //return soft valid since we need to show how soft credits were added |
1027 | if (!empty($formatted['soft_credit'])) { | |
8dc9763a | 1028 | return self::SOFT_CREDIT; |
6a488035 | 1029 | } |
69f296a4 | 1030 | |
1031 | // process pledge payment assoc w/ the contribution | |
672b72ea | 1032 | return $this->processPledgePayments($formatted); |
6a488035 TO |
1033 | } |
1034 | ||
1035 | /** | |
74ab7ba8 EM |
1036 | * Process pledge payments. |
1037 | * | |
1038 | * @param array $formatted | |
1039 | * | |
1040 | * @return int | |
6a488035 | 1041 | */ |
672b72ea | 1042 | private function processPledgePayments(array $formatted) { |
8cc574cf | 1043 | if (!empty($formatted['pledge_payment_id']) && !empty($formatted['pledge_id'])) { |
6a488035 | 1044 | //get completed status |
593dbb07 | 1045 | $completeStatusID = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'); |
6a488035 TO |
1046 | |
1047 | //need to update payment record to map contribution_id | |
1048 | CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_PledgePayment', $formatted['pledge_payment_id'], | |
1049 | 'contribution_id', $formatted['contribution_id'] | |
1050 | ); | |
1051 | ||
1052 | CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($formatted['pledge_id'], | |
be2fb01f | 1053 | [$formatted['pledge_payment_id']], |
6a488035 TO |
1054 | $completeStatusID, |
1055 | NULL, | |
1056 | $formatted['total_amount'] | |
1057 | ); | |
1058 | ||
8dc9763a | 1059 | return self::PLEDGE_PAYMENT; |
6a488035 TO |
1060 | } |
1061 | } | |
1062 | ||
1063 | /** | |
ceb10dc7 | 1064 | * Get the array of successfully imported contribution id's |
6a488035 TO |
1065 | * |
1066 | * @return array | |
6a488035 | 1067 | */ |
00be9182 | 1068 | public function &getImportedContributions() { |
6a488035 TO |
1069 | return $this->_newContributions; |
1070 | } | |
1071 | ||
1004b689 | 1072 | /** |
1073 | * Format date fields from input to mysql. | |
1074 | * | |
1075 | * @param array $params | |
1076 | * | |
1077 | * @return array | |
1078 | * Error messages, if any. | |
1079 | */ | |
1080 | public function formatDateFields(&$params) { | |
341c643b | 1081 | $errorMessage = []; |
1004b689 | 1082 | $dateType = CRM_Core_Session::singleton()->get('dateTypes'); |
1083 | foreach ($params as $key => $val) { | |
1084 | if ($val) { | |
1085 | switch ($key) { | |
1086 | case 'receive_date': | |
1087 | if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { | |
1088 | $params[$key] = $dateValue; | |
1089 | } | |
1090 | else { | |
341c643b | 1091 | $errorMessage[] = ts('Receive Date'); |
1004b689 | 1092 | } |
1093 | break; | |
1094 | ||
1095 | case 'cancel_date': | |
1096 | if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { | |
1097 | $params[$key] = $dateValue; | |
1098 | } | |
1099 | else { | |
341c643b | 1100 | $errorMessage[] = ts('Cancel Date'); |
1004b689 | 1101 | } |
1102 | break; | |
1103 | ||
1104 | case 'receipt_date': | |
1105 | if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { | |
1106 | $params[$key] = $dateValue; | |
1107 | } | |
1108 | else { | |
341c643b | 1109 | $errorMessage[] = ts('Receipt date'); |
1004b689 | 1110 | } |
1111 | break; | |
1112 | ||
1113 | case 'thankyou_date': | |
1114 | if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { | |
1115 | $params[$key] = $dateValue; | |
1116 | } | |
1117 | else { | |
341c643b | 1118 | $errorMessage[] = ts('Thankyou Date'); |
1004b689 | 1119 | } |
1120 | break; | |
1121 | } | |
1122 | } | |
1123 | } | |
1124 | return $errorMessage; | |
1125 | } | |
1126 | ||
1127 | /** | |
1128 | * Format input params to suit api handling. | |
1129 | * | |
4fc2ce46 | 1130 | * Over time all the parts of deprecatedFormatParams |
1004b689 | 1131 | * and all the parts of the import function on this class that relate to |
1132 | * reformatting input should be moved here and tests should be added in | |
1133 | * CRM_Contribute_Import_Parser_ContributionTest. | |
1134 | * | |
1135 | * @param array $params | |
fed96c11 | 1136 | * @param array $formatted |
1004b689 | 1137 | */ |
fed96c11 | 1138 | public function formatInput(&$params, &$formatted = []) { |
1004b689 | 1139 | $dateType = CRM_Core_Session::singleton()->get('dateTypes'); |
1140 | $customDataType = !empty($params['contact_type']) ? $params['contact_type'] : 'Contribution'; | |
1141 | $customFields = CRM_Core_BAO_CustomField::getFields($customDataType); | |
1142 | // @todo call formatDateFields & move custom data handling there. | |
4fc2ce46 | 1143 | // Also note error handling for dates is currently in deprecatedFormatParams |
1004b689 | 1144 | // we should use the error handling in formatDateFields. |
1145 | foreach ($params as $key => $val) { | |
1146 | // @todo - call formatDateFields instead. | |
1147 | if ($val) { | |
1148 | switch ($key) { | |
1149 | case 'receive_date': | |
1150 | case 'cancel_date': | |
1151 | case 'receipt_date': | |
1152 | case 'thankyou_date': | |
1153 | $params[$key] = CRM_Utils_Date::formatDate($params[$key], $dateType); | |
1154 | break; | |
1155 | ||
1156 | case 'pledge_payment': | |
1157 | $params[$key] = CRM_Utils_String::strtobool($val); | |
1158 | break; | |
1159 | ||
1160 | } | |
1161 | if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { | |
1162 | if ($customFields[$customFieldID]['data_type'] == 'Date') { | |
fed96c11 | 1163 | CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key); |
1004b689 | 1164 | unset($params[$key]); |
1165 | } | |
1166 | elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { | |
1167 | $params[$key] = CRM_Utils_String::strtoboolstr($val); | |
1168 | } | |
1169 | } | |
1170 | } | |
1171 | } | |
1172 | } | |
1173 | ||
4fc2ce46 | 1174 | /** |
1175 | * take the input parameter list as specified in the data model and | |
1176 | * convert it into the same format that we use in QF and BAO object | |
1177 | * | |
1178 | * @param array $params | |
5e21e0f3 BT |
1179 | * Associative array of property name/value |
1180 | * pairs to insert in new contact. | |
4fc2ce46 | 1181 | * @param array $values |
1182 | * The reformatted properties that we can use internally. | |
4fc2ce46 | 1183 | * @param bool $create |
5e21e0f3 | 1184 | * @param int $onDuplicate |
4fc2ce46 | 1185 | * |
1186 | * @return array|CRM_Error | |
1187 | */ | |
1188 | private function deprecatedFormatParams($params, &$values, $create = FALSE, $onDuplicate = NULL) { | |
1189 | require_once 'CRM/Utils/DeprecatedUtils.php'; | |
1190 | // copy all the contribution fields as is | |
1191 | require_once 'api/v3/utils.php'; | |
315a6e2a | 1192 | $fields = CRM_Core_DAO::getExportableFieldsWithPseudoConstants('CRM_Contribute_BAO_Contribution'); |
4fc2ce46 | 1193 | |
1194 | _civicrm_api3_store_values($fields, $params, $values); | |
1195 | ||
4fc2ce46 | 1196 | $customFields = CRM_Core_BAO_CustomField::getFields('Contribution', FALSE, FALSE, NULL, NULL, FALSE, FALSE, FALSE); |
1197 | ||
1198 | foreach ($params as $key => $value) { | |
1199 | // ignore empty values or empty arrays etc | |
1200 | if (CRM_Utils_System::isNull($value)) { | |
1201 | continue; | |
1202 | } | |
1203 | ||
1204 | // Handling Custom Data | |
1205 | if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { | |
1206 | $values[$key] = $value; | |
1207 | $type = $customFields[$customFieldID]['html_type']; | |
726e45e7 | 1208 | if (CRM_Core_BAO_CustomField::isSerialized($customFields[$customFieldID])) { |
be40742b | 1209 | $values[$key] = self::unserializeCustomValue($customFieldID, $value, $type); |
4fc2ce46 | 1210 | } |
1211 | elseif ($type == 'Select' || $type == 'Radio' || | |
1212 | ($type == 'Autocomplete-Select' && | |
1213 | $customFields[$customFieldID]['data_type'] == 'String' | |
1214 | ) | |
1215 | ) { | |
1216 | $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE); | |
1217 | foreach ($customOption as $customFldID => $customValue) { | |
9c1bc317 CW |
1218 | $val = $customValue['value'] ?? NULL; |
1219 | $label = $customValue['label'] ?? NULL; | |
4fc2ce46 | 1220 | $label = strtolower($label); |
1221 | $value = strtolower(trim($value)); | |
1222 | if (($value == $label) || ($value == strtolower($val))) { | |
1223 | $values[$key] = $val; | |
1224 | } | |
1225 | } | |
1226 | } | |
769fea07 | 1227 | continue; |
4fc2ce46 | 1228 | } |
1229 | ||
1230 | switch ($key) { | |
1231 | case 'contribution_contact_id': | |
1232 | if (!CRM_Utils_Rule::integer($value)) { | |
1233 | return civicrm_api3_create_error("contact_id not valid: $value"); | |
1234 | } | |
1235 | $dao = new CRM_Core_DAO(); | |
1236 | $qParams = []; | |
1237 | $svq = $dao->singleValueQuery("SELECT is_deleted FROM civicrm_contact WHERE id = $value", | |
1238 | $qParams | |
1239 | ); | |
1240 | if (!isset($svq)) { | |
1241 | return civicrm_api3_create_error("Invalid Contact ID: There is no contact record with contact_id = $value."); | |
1242 | } | |
1243 | elseif ($svq == 1) { | |
1244 | return civicrm_api3_create_error("Invalid Contact ID: contact_id $value is a soft-deleted contact."); | |
1245 | } | |
1246 | ||
1247 | $values['contact_id'] = $values['contribution_contact_id']; | |
1248 | unset($values['contribution_contact_id']); | |
1249 | break; | |
1250 | ||
1251 | case 'contact_type': | |
1252 | // import contribution record according to select contact type | |
1253 | require_once 'CRM/Contact/DAO/Contact.php'; | |
1254 | $contactType = new CRM_Contact_DAO_Contact(); | |
9c1bc317 CW |
1255 | $contactId = $params['contribution_contact_id'] ?? NULL; |
1256 | $externalId = $params['external_identifier'] ?? NULL; | |
1257 | $email = $params['email'] ?? NULL; | |
4fc2ce46 | 1258 | //when insert mode check contact id or external identifier |
1259 | if ($contactId || $externalId) { | |
1260 | $contactType->id = $contactId; | |
1261 | $contactType->external_identifier = $externalId; | |
1262 | if ($contactType->find(TRUE)) { | |
1263 | if ($params['contact_type'] != $contactType->contact_type) { | |
1264 | return civicrm_api3_create_error("Contact Type is wrong: $contactType->contact_type"); | |
1265 | } | |
1266 | } | |
1267 | } | |
1268 | elseif ($email) { | |
1269 | if (!CRM_Utils_Rule::email($email)) { | |
1270 | return civicrm_api3_create_error("Invalid email address $email provided. Row was skipped"); | |
1271 | } | |
1272 | ||
1273 | // get the contact id from duplicate contact rule, if more than one contact is returned | |
1274 | // we should return error, since current interface allows only one-one mapping | |
69f296a4 | 1275 | $emailParams = [ |
1276 | 'email' => $email, | |
1277 | 'contact_type' => $params['contact_type'], | |
1278 | ]; | |
4fc2ce46 | 1279 | $checkDedupe = _civicrm_api3_deprecated_duplicate_formatted_contact($emailParams); |
1280 | if (!$checkDedupe['is_error']) { | |
1281 | return civicrm_api3_create_error("Invalid email address(doesn't exist) $email. Row was skipped"); | |
1282 | } | |
69f296a4 | 1283 | $matchingContactIds = explode(',', $checkDedupe['error_message']['params'][0]); |
1284 | if (count($matchingContactIds) > 1) { | |
1285 | return civicrm_api3_create_error("Invalid email address(duplicate) $email. Row was skipped"); | |
1286 | } | |
1287 | if (count($matchingContactIds) == 1) { | |
1288 | $params['contribution_contact_id'] = $matchingContactIds[0]; | |
4fc2ce46 | 1289 | } |
1290 | } | |
1291 | elseif (!empty($params['contribution_id']) || !empty($params['trxn_id']) || !empty($params['invoice_id'])) { | |
1292 | // when update mode check contribution id or trxn id or | |
1293 | // invoice id | |
1294 | $contactId = new CRM_Contribute_DAO_Contribution(); | |
1295 | if (!empty($params['contribution_id'])) { | |
1296 | $contactId->id = $params['contribution_id']; | |
1297 | } | |
1298 | elseif (!empty($params['trxn_id'])) { | |
1299 | $contactId->trxn_id = $params['trxn_id']; | |
1300 | } | |
1301 | elseif (!empty($params['invoice_id'])) { | |
1302 | $contactId->invoice_id = $params['invoice_id']; | |
1303 | } | |
1304 | if ($contactId->find(TRUE)) { | |
1305 | $contactType->id = $contactId->contact_id; | |
1306 | if ($contactType->find(TRUE)) { | |
1307 | if ($params['contact_type'] != $contactType->contact_type) { | |
1308 | return civicrm_api3_create_error("Contact Type is wrong: $contactType->contact_type"); | |
1309 | } | |
1310 | } | |
1311 | } | |
1312 | } | |
1313 | else { | |
1314 | if ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE) { | |
1315 | return civicrm_api3_create_error("Empty Contribution and Invoice and Transaction ID. Row was skipped."); | |
1316 | } | |
1317 | } | |
1318 | break; | |
1319 | ||
1320 | case 'receive_date': | |
1321 | case 'cancel_date': | |
1322 | case 'receipt_date': | |
1323 | case 'thankyou_date': | |
1324 | if (!CRM_Utils_Rule::dateTime($value)) { | |
1325 | return civicrm_api3_create_error("$key not a valid date: $value"); | |
1326 | } | |
1327 | break; | |
1328 | ||
1329 | case 'non_deductible_amount': | |
1330 | case 'total_amount': | |
1331 | case 'fee_amount': | |
1332 | case 'net_amount': | |
8e2ac367 | 1333 | // @todo add test like testPaymentTypeLabel & remove these lines as we can anticipate error will still be caught & handled. |
4fc2ce46 | 1334 | if (!CRM_Utils_Rule::money($value)) { |
1335 | return civicrm_api3_create_error("$key not a valid amount: $value"); | |
1336 | } | |
1337 | break; | |
1338 | ||
1339 | case 'currency': | |
1340 | if (!CRM_Utils_Rule::currencyCode($value)) { | |
1341 | return civicrm_api3_create_error("currency not a valid code: $value"); | |
1342 | } | |
1343 | break; | |
1344 | ||
1345 | case 'financial_type': | |
315a6e2a | 1346 | // @todo add test like testPaymentTypeLabel & remove these lines in favour of 'default' part of switch. |
4fc2ce46 | 1347 | require_once 'CRM/Contribute/PseudoConstant.php'; |
1348 | $contriTypes = CRM_Contribute_PseudoConstant::financialType(); | |
1349 | foreach ($contriTypes as $val => $type) { | |
1350 | if (strtolower($value) == strtolower($type)) { | |
1351 | $values['financial_type_id'] = $val; | |
1352 | break; | |
1353 | } | |
1354 | } | |
1355 | if (empty($values['financial_type_id'])) { | |
1356 | return civicrm_api3_create_error("Financial Type is not valid: $value"); | |
1357 | } | |
1358 | break; | |
1359 | ||
4fc2ce46 | 1360 | case 'soft_credit': |
1361 | // import contribution record according to select contact type | |
1362 | // validate contact id and external identifier. | |
1363 | $value[$key] = $mismatchContactType = $softCreditContactIds = ''; | |
1364 | if (isset($params[$key]) && is_array($params[$key])) { | |
1365 | foreach ($params[$key] as $softKey => $softParam) { | |
9c1bc317 CW |
1366 | $contactId = $softParam['contact_id'] ?? NULL; |
1367 | $externalId = $softParam['external_identifier'] ?? NULL; | |
1368 | $email = $softParam['email'] ?? NULL; | |
4fc2ce46 | 1369 | if ($contactId || $externalId) { |
1370 | require_once 'CRM/Contact/DAO/Contact.php'; | |
1371 | $contact = new CRM_Contact_DAO_Contact(); | |
1372 | $contact->id = $contactId; | |
1373 | $contact->external_identifier = $externalId; | |
1374 | $errorMsg = NULL; | |
1375 | if (!$contact->find(TRUE)) { | |
1376 | $field = $contactId ? ts('Contact ID') : ts('External ID'); | |
1377 | $errorMsg = ts("Soft Credit %1 - %2 doesn't exist. Row was skipped.", | |
1378 | [1 => $field, 2 => $contactId ? $contactId : $externalId]); | |
1379 | } | |
1380 | ||
1381 | if ($errorMsg) { | |
1382 | return civicrm_api3_create_error($errorMsg); | |
1383 | } | |
1384 | ||
1385 | // finally get soft credit contact id. | |
1386 | $values[$key][$softKey] = $softParam; | |
1387 | $values[$key][$softKey]['contact_id'] = $contact->id; | |
1388 | } | |
1389 | elseif ($email) { | |
1390 | if (!CRM_Utils_Rule::email($email)) { | |
1391 | return civicrm_api3_create_error("Invalid email address $email provided for Soft Credit. Row was skipped"); | |
1392 | } | |
1393 | ||
1394 | // get the contact id from duplicate contact rule, if more than one contact is returned | |
1395 | // we should return error, since current interface allows only one-one mapping | |
69f296a4 | 1396 | $emailParams = [ |
1397 | 'email' => $email, | |
1398 | 'contact_type' => $params['contact_type'], | |
1399 | ]; | |
4fc2ce46 | 1400 | $checkDedupe = _civicrm_api3_deprecated_duplicate_formatted_contact($emailParams); |
1401 | if (!$checkDedupe['is_error']) { | |
1402 | return civicrm_api3_create_error("Invalid email address(doesn't exist) $email for Soft Credit. Row was skipped"); | |
1403 | } | |
69f296a4 | 1404 | $matchingContactIds = explode(',', $checkDedupe['error_message']['params'][0]); |
1405 | if (count($matchingContactIds) > 1) { | |
1406 | return civicrm_api3_create_error("Invalid email address(duplicate) $email for Soft Credit. Row was skipped"); | |
1407 | } | |
1408 | if (count($matchingContactIds) == 1) { | |
1409 | $contactId = $matchingContactIds[0]; | |
1410 | unset($softParam['email']); | |
1411 | $values[$key][$softKey] = $softParam + ['contact_id' => $contactId]; | |
4fc2ce46 | 1412 | } |
1413 | } | |
1414 | } | |
1415 | } | |
1416 | break; | |
1417 | ||
1418 | case 'pledge_payment': | |
1419 | case 'pledge_id': | |
1420 | ||
1421 | // giving respect to pledge_payment flag. | |
1422 | if (empty($params['pledge_payment'])) { | |
c237e286 | 1423 | break; |
4fc2ce46 | 1424 | } |
1425 | ||
1426 | // get total amount of from import fields | |
9c1bc317 | 1427 | $totalAmount = $params['total_amount'] ?? NULL; |
4fc2ce46 | 1428 | |
9c1bc317 | 1429 | $onDuplicate = $params['onDuplicate'] ?? NULL; |
4fc2ce46 | 1430 | |
1431 | // we need to get contact id $contributionContactID to | |
1432 | // retrieve pledge details as well as to validate pledge ID | |
1433 | ||
1434 | // first need to check for update mode | |
1435 | if ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE && | |
1436 | ($params['contribution_id'] || $params['trxn_id'] || $params['invoice_id']) | |
1437 | ) { | |
1438 | $contribution = new CRM_Contribute_DAO_Contribution(); | |
1439 | if ($params['contribution_id']) { | |
1440 | $contribution->id = $params['contribution_id']; | |
1441 | } | |
1442 | elseif ($params['trxn_id']) { | |
1443 | $contribution->trxn_id = $params['trxn_id']; | |
1444 | } | |
1445 | elseif ($params['invoice_id']) { | |
1446 | $contribution->invoice_id = $params['invoice_id']; | |
1447 | } | |
1448 | ||
1449 | if ($contribution->find(TRUE)) { | |
1450 | $contributionContactID = $contribution->contact_id; | |
1451 | if (!$totalAmount) { | |
1452 | $totalAmount = $contribution->total_amount; | |
1453 | } | |
1454 | } | |
1455 | else { | |
1456 | return civicrm_api3_create_error('No match found for specified contact in pledge payment data. Row was skipped.'); | |
1457 | } | |
1458 | } | |
1459 | else { | |
1460 | // first get the contact id for given contribution record. | |
1461 | if (!empty($params['contribution_contact_id'])) { | |
1462 | $contributionContactID = $params['contribution_contact_id']; | |
1463 | } | |
1464 | elseif (!empty($params['external_identifier'])) { | |
1465 | require_once 'CRM/Contact/DAO/Contact.php'; | |
1466 | $contact = new CRM_Contact_DAO_Contact(); | |
1467 | $contact->external_identifier = $params['external_identifier']; | |
1468 | if ($contact->find(TRUE)) { | |
1469 | $contributionContactID = $params['contribution_contact_id'] = $values['contribution_contact_id'] = $contact->id; | |
1470 | } | |
1471 | else { | |
1472 | return civicrm_api3_create_error('No match found for specified contact in pledge payment data. Row was skipped.'); | |
1473 | } | |
1474 | } | |
1475 | else { | |
1476 | // we need to get contribution contact using de dupe | |
95519b12 | 1477 | $error = $this->checkContactDuplicate($params); |
4fc2ce46 | 1478 | |
1479 | if (isset($error['error_message']['params'][0])) { | |
1480 | $matchedIDs = explode(',', $error['error_message']['params'][0]); | |
1481 | ||
1482 | // check if only one contact is found | |
1483 | if (count($matchedIDs) > 1) { | |
1484 | return civicrm_api3_create_error($error['error_message']['message']); | |
1485 | } | |
69f296a4 | 1486 | $contributionContactID = $params['contribution_contact_id'] = $values['contribution_contact_id'] = $matchedIDs[0]; |
4fc2ce46 | 1487 | } |
1488 | else { | |
1489 | return civicrm_api3_create_error('No match found for specified contact in contribution data. Row was skipped.'); | |
1490 | } | |
1491 | } | |
1492 | } | |
1493 | ||
1494 | if (!empty($params['pledge_id'])) { | |
1495 | if (CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_Pledge', $params['pledge_id'], 'contact_id') != $contributionContactID) { | |
1496 | return civicrm_api3_create_error('Invalid Pledge ID provided. Contribution row was skipped.'); | |
1497 | } | |
1498 | $values['pledge_id'] = $params['pledge_id']; | |
1499 | } | |
1500 | else { | |
1501 | // check if there are any pledge related to this contact, with payments pending or in progress | |
1502 | require_once 'CRM/Pledge/BAO/Pledge.php'; | |
1503 | $pledgeDetails = CRM_Pledge_BAO_Pledge::getContactPledges($contributionContactID); | |
1504 | ||
1505 | if (empty($pledgeDetails)) { | |
1506 | return civicrm_api3_create_error('No open pledges found for this contact. Contribution row was skipped.'); | |
1507 | } | |
69f296a4 | 1508 | if (count($pledgeDetails) > 1) { |
4fc2ce46 | 1509 | return civicrm_api3_create_error('This contact has more than one open pledge. Unable to determine which pledge to apply the contribution to. Contribution row was skipped.'); |
1510 | } | |
1511 | ||
1512 | // this mean we have only one pending / in progress pledge | |
1513 | $values['pledge_id'] = $pledgeDetails[0]; | |
1514 | } | |
1515 | ||
1516 | // we need to check if oldest payment amount equal to contribution amount | |
1517 | require_once 'CRM/Pledge/BAO/PledgePayment.php'; | |
1518 | $pledgePaymentDetails = CRM_Pledge_BAO_PledgePayment::getOldestPledgePayment($values['pledge_id']); | |
1519 | ||
1520 | if ($pledgePaymentDetails['amount'] == $totalAmount) { | |
1521 | $values['pledge_payment_id'] = $pledgePaymentDetails['id']; | |
1522 | } | |
1523 | else { | |
1524 | return civicrm_api3_create_error('Contribution and Pledge Payment amount mismatch for this record. Contribution row was skipped.'); | |
1525 | } | |
1526 | break; | |
1527 | ||
cb9cdda8 KJ |
1528 | case 'contribution_campaign_id': |
1529 | if (empty(CRM_Core_DAO::getFieldValue('CRM_Campaign_DAO_Campaign', $params['contribution_campaign_id']))) { | |
1530 | return civicrm_api3_create_error('Invalid Campaign ID provided. Contribution row was skipped.'); | |
1531 | } | |
1532 | $values['contribution_campaign_id'] = $params['contribution_campaign_id']; | |
1533 | break; | |
1534 | ||
4fc2ce46 | 1535 | default: |
8e2ac367 | 1536 | // Hande name or label for fields with options. |
1537 | if (isset($fields[$key]) && | |
1538 | // Yay - just for a surprise we are inconsistent on whether we pass the pseudofield (payment_instrument) | |
1539 | // or the field name (contribution_status_id) | |
1540 | (!empty($fields[$key]['is_pseudofield_for']) || !empty($fields[$key]['pseudoconstant'])) | |
1541 | ) { | |
1542 | $realField = $fields[$key]['is_pseudofield_for'] ?? $key; | |
315a6e2a | 1543 | $realFieldSpec = $fields[$realField]; |
14b9e069 | 1544 | $values[$key] = $this->parsePseudoConstantField($value, $realFieldSpec); |
315a6e2a | 1545 | } |
4fc2ce46 | 1546 | break; |
1547 | } | |
1548 | } | |
1549 | ||
1550 | if (array_key_exists('note', $params)) { | |
1551 | $values['note'] = $params['note']; | |
1552 | } | |
1553 | ||
1554 | if ($create) { | |
1555 | // CRM_Contribute_BAO_Contribution::add() handles contribution_source | |
1556 | // So, if $values contains contribution_source, convert it to source | |
1557 | $changes = ['contribution_source' => 'source']; | |
1558 | ||
1559 | foreach ($changes as $orgVal => $changeVal) { | |
1560 | if (isset($values[$orgVal])) { | |
1561 | $values[$changeVal] = $values[$orgVal]; | |
1562 | unset($values[$orgVal]); | |
1563 | } | |
1564 | } | |
1565 | } | |
1566 | ||
1567 | return NULL; | |
1568 | } | |
1569 | ||
73edfc10 EM |
1570 | /** |
1571 | * Get the civicrm_mapping_field appropriate layout for the mapper input. | |
1572 | * | |
1573 | * The input looks something like ['street_address', 1] | |
1574 | * and would be mapped to ['name' => 'street_address', 'location_type_id' => | |
1575 | * 1] | |
1576 | * | |
1577 | * @param array $fieldMapping | |
1578 | * @param int $mappingID | |
1579 | * @param int $columnNumber | |
1580 | * | |
1581 | * @return array | |
1582 | * @throws \API_Exception | |
1583 | */ | |
1584 | public function getMappingFieldFromMapperInput(array $fieldMapping, int $mappingID, int $columnNumber): array { | |
1585 | $isRelationshipField = preg_match('/\d*_a_b|b_a$/', $fieldMapping[0]); | |
1586 | $fieldName = $isRelationshipField ? $fieldMapping[1] : $fieldMapping[0]; | |
1587 | return [ | |
1588 | 'name' => $fieldMapping[0], | |
1589 | 'mapping_id' => $mappingID, | |
1590 | 'column_number' => $columnNumber, | |
1591 | // The name of the field to match the soft credit on is (crazily) | |
1592 | // stored in 'contact_type' | |
1593 | 'contact_type' => $fieldMapping[1] ?? NULL, | |
1594 | // We also store the field in a sensible key, even if it isn't saved sensibly. | |
1595 | 'soft_credit_match_field' => $fieldMapping[1] ?? NULL, | |
1596 | // This field is actually not saved at all :-( It is lost each time. | |
1597 | 'soft_credit_type_id' => $fieldMapping[2] ?? NULL, | |
1598 | ]; | |
1599 | } | |
1600 | ||
6a488035 | 1601 | } |