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