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