commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / CRM / Contribute / Import / Parser / Contribution.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2015
32 * $Id$
33 *
34 */
35
36 /**
37 * Class to parse contribution csv files.
38 */
39 class CRM_Contribute_Import_Parser_Contribution extends CRM_Contribute_Import_Parser {
40
41 protected $_mapperKeys;
42
43 private $_contactIdIndex;
44 private $_totalAmountIndex;
45 private $_contributionTypeIndex;
46
47 protected $_mapperSoftCredit;
48 //protected $_mapperPhoneType;
49
50 /**
51 * Array of successfully imported contribution id's
52 *
53 * @array
54 */
55 protected $_newContributions;
56
57 /**
58 * Class constructor.
59 *
60 * @param $mapperKeys
61 * @param null $mapperSoftCredit
62 * @param null $mapperPhoneType
63 * @param null $mapperSoftCreditType
64 */
65 public function __construct(&$mapperKeys, $mapperSoftCredit = NULL, $mapperPhoneType = NULL, $mapperSoftCreditType = NULL) {
66 parent::__construct();
67 $this->_mapperKeys = &$mapperKeys;
68 $this->_mapperSoftCredit = &$mapperSoftCredit;
69 $this->_mapperSoftCreditType = &$mapperSoftCreditType;
70 }
71
72 /**
73 * The initializer code, called before the processing
74 *
75 * @return void
76 */
77 public function init() {
78 $fields = CRM_Contribute_BAO_Contribution::importableFields($this->_contactType, FALSE);
79
80 $fields = array_merge($fields,
81 array(
82 'soft_credit' => array(
83 'title' => ts('Soft Credit'),
84 'softCredit' => TRUE,
85 'headerPattern' => '/Soft Credit/i',
86 ),
87 )
88 );
89
90 // add pledge fields only if its is enabled
91 if (CRM_Core_Permission::access('CiviPledge')) {
92 $pledgeFields = array(
93 'pledge_payment' => array(
94 'title' => ts('Pledge Payment'),
95 'headerPattern' => '/Pledge Payment/i',
96 ),
97 'pledge_id' => array(
98 'title' => ts('Pledge ID'),
99 'headerPattern' => '/Pledge ID/i',
100 ),
101 );
102
103 $fields = array_merge($fields, $pledgeFields);
104 }
105 foreach ($fields as $name => $field) {
106 $field['type'] = CRM_Utils_Array::value('type', $field, CRM_Utils_Type::T_INT);
107 $field['dataPattern'] = CRM_Utils_Array::value('dataPattern', $field, '//');
108 $field['headerPattern'] = CRM_Utils_Array::value('headerPattern', $field, '//');
109 $this->addField($name, $field['title'], $field['type'], $field['headerPattern'], $field['dataPattern']);
110 }
111
112 $this->_newContributions = array();
113
114 $this->setActiveFields($this->_mapperKeys);
115 $this->setActiveFieldSoftCredit($this->_mapperSoftCredit);
116 $this->setActiveFieldSoftCreditType($this->_mapperSoftCreditType);
117
118 // FIXME: we should do this in one place together with Form/MapField.php
119 $this->_contactIdIndex = -1;
120 $this->_totalAmountIndex = -1;
121 $this->_contributionTypeIndex = -1;
122
123 $index = 0;
124 foreach ($this->_mapperKeys as $key) {
125 switch ($key) {
126 case 'contribution_contact_id':
127 $this->_contactIdIndex = $index;
128 break;
129
130 case 'total_amount':
131 $this->_totalAmountIndex = $index;
132 break;
133
134 case 'financial_type':
135 $this->_contributionTypeIndex = $index;
136 break;
137 }
138 $index++;
139 }
140 }
141
142 /**
143 * Handle the values in mapField mode.
144 *
145 * @param array $values
146 * The array of values belonging to this line.
147 *
148 * @return bool
149 */
150 public function mapField(&$values) {
151 return CRM_Import_Parser::VALID;
152 }
153
154 /**
155 * Handle the values in preview mode.
156 *
157 * @param array $values
158 * The array of values belonging to this line.
159 *
160 * @return bool
161 * the result of this processing
162 */
163 public function preview(&$values) {
164 return $this->summary($values);
165 }
166
167 /**
168 * Handle the values in summary mode.
169 *
170 * @param array $values
171 * The array of values belonging to this line.
172 *
173 * @return bool
174 * the result of this processing
175 */
176 public function summary(&$values) {
177 $erroneousField = NULL;
178 $response = $this->setActiveFieldValues($values, $erroneousField);
179
180 $params = &$this->getActiveFieldParams();
181 $errorMessage = NULL;
182
183 //for date-Formats
184 $session = CRM_Core_Session::singleton();
185 $dateType = $session->get('dateTypes');
186 foreach ($params as $key => $val) {
187 if ($val) {
188 switch ($key) {
189 case 'receive_date':
190 if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) {
191 $params[$key] = $dateValue;
192 }
193 else {
194 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receive Date', $errorMessage);
195 }
196 break;
197
198 case 'cancel_date':
199 if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) {
200 $params[$key] = $dateValue;
201 }
202 else {
203 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Cancel Date', $errorMessage);
204 }
205 break;
206
207 case 'receipt_date':
208 if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) {
209 $params[$key] = $dateValue;
210 }
211 else {
212 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receipt date', $errorMessage);
213 }
214 break;
215
216 case 'thankyou_date':
217 if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) {
218 $params[$key] = $dateValue;
219 }
220 else {
221 CRM_Contact_Import_Parser_Contact::addToErrorMsg('Thankyou Date', $errorMessage);
222 }
223 break;
224 }
225 }
226 }
227 //date-Format part ends
228
229 $params['contact_type'] = 'Contribution';
230
231 //checking error in custom data
232 CRM_Contact_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage);
233
234 if ($errorMessage) {
235 $tempMsg = "Invalid value for field(s) : $errorMessage";
236 array_unshift($values, $tempMsg);
237 $errorMessage = NULL;
238 return CRM_Import_Parser::ERROR;
239 }
240
241 return CRM_Import_Parser::VALID;
242 }
243
244 /**
245 * Handle the values in import mode.
246 *
247 * @param int $onDuplicate
248 * The code for what action to take on duplicates.
249 * @param array $values
250 * The array of values belonging to this line.
251 *
252 * @return bool
253 * the result of this processing
254 */
255 public function import($onDuplicate, &$values) {
256 // first make sure this is a valid line
257 $response = $this->summary($values);
258 if ($response != CRM_Import_Parser::VALID) {
259 return $response;
260 }
261
262 $params = &$this->getActiveFieldParams();
263 $formatted = array('version' => 3);
264
265 // don't add to recent items, CRM-4399
266 $formatted['skipRecentView'] = TRUE;
267
268 //for date-Formats
269 $session = CRM_Core_Session::singleton();
270 $dateType = $session->get('dateTypes');
271
272 $customDataType = !empty($params['contact_type']) ? $params['contact_type'] : 'Contribution';
273 $customFields = CRM_Core_BAO_CustomField::getFields($customDataType);
274
275 //CRM-10994
276 if (isset($params['total_amount']) && $params['total_amount'] == 0) {
277 $params['total_amount'] = '0.00';
278 }
279 foreach ($params as $key => $val) {
280 if ($val) {
281 switch ($key) {
282 case 'receive_date':
283 case 'cancel_date':
284 case 'receipt_date':
285 case 'thankyou_date':
286 $params[$key] = CRM_Utils_Date::formatDate($params[$key], $dateType);
287 break;
288
289 case 'pledge_payment':
290 $params[$key] = CRM_Utils_String::strtobool($val);
291 break;
292
293 }
294 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
295 if ($customFields[$customFieldID]['data_type'] == 'Date') {
296 CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key);
297 unset($params[$key]);
298 }
299 elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') {
300 $params[$key] = CRM_Utils_String::strtoboolstr($val);
301 }
302 }
303 }
304 }
305 //date-Format part ends
306
307 static $indieFields = NULL;
308 if ($indieFields == NULL) {
309 $tempIndieFields = CRM_Contribute_DAO_Contribution::import();
310 $indieFields = $tempIndieFields;
311 }
312
313 $paramValues = array();
314 foreach ($params as $key => $field) {
315 if ($field == NULL || $field === '') {
316 continue;
317 }
318 $paramValues[$key] = $field;
319 }
320
321 //import contribution record according to select contact type
322 if ($onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP &&
323 (!empty($paramValues['contribution_contact_id']) || !empty($paramValues['external_identifier']))
324 ) {
325 $paramValues['contact_type'] = $this->_contactType;
326 }
327 elseif ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE &&
328 (!empty($paramValues['contribution_id']) || !empty($values['trxn_id']) || !empty($paramValues['invoice_id']))
329 ) {
330 $paramValues['contact_type'] = $this->_contactType;
331 }
332 elseif (!empty($params['soft_credit'])) {
333 $paramValues['contact_type'] = $this->_contactType;
334 }
335 elseif (!empty($paramValues['pledge_payment'])) {
336 $paramValues['contact_type'] = $this->_contactType;
337 }
338
339 //need to pass $onDuplicate to check import mode.
340 if (!empty($paramValues['pledge_payment'])) {
341 $paramValues['onDuplicate'] = $onDuplicate;
342 }
343 require_once 'CRM/Utils/DeprecatedUtils.php';
344 $formatError = _civicrm_api3_deprecated_formatted_param($paramValues, $formatted, TRUE, $onDuplicate);
345
346 if ($formatError) {
347 array_unshift($values, $formatError['error_message']);
348 if (CRM_Utils_Array::value('error_data', $formatError) == 'soft_credit') {
349 return CRM_Contribute_Import_Parser::SOFT_CREDIT_ERROR;
350 }
351 elseif (CRM_Utils_Array::value('error_data', $formatError) == 'pledge_payment') {
352 return CRM_Contribute_Import_Parser::PLEDGE_PAYMENT_ERROR;
353 }
354 return CRM_Import_Parser::ERROR;
355 }
356
357 if ($onDuplicate != CRM_Import_Parser::DUPLICATE_UPDATE) {
358 $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted,
359 CRM_Core_DAO::$_nullObject,
360 NULL,
361 'Contribution'
362 );
363 }
364 else {
365 //fix for CRM-2219 - Update Contribution
366 // onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE
367 if (!empty($paramValues['invoice_id']) || !empty($paramValues['trxn_id']) || !empty($paramValues['contribution_id'])) {
368 $dupeIds = array(
369 'id' => CRM_Utils_Array::value('contribution_id', $paramValues),
370 'trxn_id' => CRM_Utils_Array::value('trxn_id', $paramValues),
371 'invoice_id' => CRM_Utils_Array::value('invoice_id', $paramValues),
372 );
373
374 $ids['contribution'] = CRM_Contribute_BAO_Contribution::checkDuplicateIds($dupeIds);
375
376 if ($ids['contribution']) {
377 $formatted['id'] = $ids['contribution'];
378 $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted,
379 CRM_Core_DAO::$_nullObject,
380 $formatted['id'],
381 'Contribution'
382 );
383 //process note
384 if (!empty($paramValues['note'])) {
385 $noteID = array();
386 $contactID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $ids['contribution'], 'contact_id');
387 $daoNote = new CRM_Core_BAO_Note();
388 $daoNote->entity_table = 'civicrm_contribution';
389 $daoNote->entity_id = $ids['contribution'];
390 if ($daoNote->find(TRUE)) {
391 $noteID['id'] = $daoNote->id;
392 }
393
394 $noteParams = array(
395 'entity_table' => 'civicrm_contribution',
396 'note' => $paramValues['note'],
397 'entity_id' => $ids['contribution'],
398 'contact_id' => $contactID,
399 );
400 CRM_Core_BAO_Note::add($noteParams, $noteID);
401 unset($formatted['note']);
402 }
403
404 //need to check existing soft credit contribution, CRM-3968
405 if (!empty($formatted['soft_credit'])) {
406 $dupeSoftCredit = array(
407 'contact_id' => $formatted['soft_credit'],
408 'contribution_id' => $ids['contribution'],
409 );
410
411 //Delete all existing soft Contribution from contribution_soft table for pcp_id is_null
412 $existingSoftCredit = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($dupeSoftCredit['contribution_id']);
413 if (isset($existingSoftCredit['soft_credit']) && !empty($existingSoftCredit['soft_credit'])) {
414 foreach ($existingSoftCredit['soft_credit'] as $key => $existingSoftCreditValues) {
415 if (!empty($existingSoftCreditValues['soft_credit_id'])) {
416 $deleteParams = array(
417 'id' => $existingSoftCreditValues['soft_credit_id'],
418 'pcp_id' => NULL,
419 );
420 CRM_Contribute_BAO_ContributionSoft::del($deleteParams);
421 }
422 }
423 }
424 }
425
426 $newContribution = CRM_Contribute_BAO_Contribution::create($formatted, $ids);
427 $this->_newContributions[] = $newContribution->id;
428
429 //return soft valid since we need to show how soft credits were added
430 if (!empty($formatted['soft_credit'])) {
431 return CRM_Contribute_Import_Parser::SOFT_CREDIT;
432 }
433
434 // process pledge payment assoc w/ the contribution
435 return self::processPledgePayments($formatted);
436
437 return CRM_Import_Parser::VALID;
438 }
439 else {
440 $labels = array(
441 'id' => 'Contribution ID',
442 'trxn_id' => 'Transaction ID',
443 'invoice_id' => 'Invoice ID',
444 );
445 foreach ($dupeIds as $k => $v) {
446 if ($v) {
447 $errorMsg[] = "$labels[$k] $v";
448 }
449 }
450 $errorMsg = implode(' AND ', $errorMsg);
451 array_unshift($values, 'Matching Contribution record not found for ' . $errorMsg . '. Row was skipped.');
452 return CRM_Import_Parser::ERROR;
453 }
454 }
455 }
456
457 if ($this->_contactIdIndex < 0) {
458 // set the contact type if its not set
459 if (!isset($paramValues['contact_type'])) {
460 $paramValues['contact_type'] = $this->_contactType;
461 }
462
463 $paramValues['version'] = 3;
464 //retrieve contact id using contact dedupe rule
465 require_once 'CRM/Utils/DeprecatedUtils.php';
466 $error = _civicrm_api3_deprecated_check_contact_dedupe($paramValues);
467
468 if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) {
469 $matchedIDs = explode(',', $error['error_message']['params'][0]);
470 if (count($matchedIDs) > 1) {
471 array_unshift($values, 'Multiple matching contact records detected for this row. The contribution was not imported');
472 return CRM_Import_Parser::ERROR;
473 }
474 else {
475 $cid = $matchedIDs[0];
476 $formatted['contact_id'] = $cid;
477
478 $newContribution = civicrm_api('contribution', 'create', $formatted);
479 if (civicrm_error($newContribution)) {
480 if (is_array($newContribution['error_message'])) {
481 array_unshift($values, $newContribution['error_message']['message']);
482 if ($newContribution['error_message']['params'][0]) {
483 return CRM_Import_Parser::DUPLICATE;
484 }
485 }
486 else {
487 array_unshift($values, $newContribution['error_message']);
488 return CRM_Import_Parser::ERROR;
489 }
490 }
491
492 $this->_newContributions[] = $newContribution['id'];
493 $formatted['contribution_id'] = $newContribution['id'];
494
495 //return soft valid since we need to show how soft credits were added
496 if (!empty($formatted['soft_credit'])) {
497 return CRM_Contribute_Import_Parser::SOFT_CREDIT;
498 }
499
500 // process pledge payment assoc w/ the contribution
501 return self::processPledgePayments($formatted);
502
503 return CRM_Import_Parser::VALID;
504 }
505 }
506 else {
507 // Using new Dedupe rule.
508 $ruleParams = array(
509 'contact_type' => $this->_contactType,
510 'used' => 'Unsupervised',
511 );
512 $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams);
513 $disp = NULL;
514 foreach ($fieldsArray as $value) {
515 if (array_key_exists(trim($value), $params)) {
516 $paramValue = $params[trim($value)];
517 if (is_array($paramValue)) {
518 $disp .= $params[trim($value)][0][trim($value)] . " ";
519 }
520 else {
521 $disp .= $params[trim($value)] . " ";
522 }
523 }
524 }
525
526 if (!empty($params['external_identifier'])) {
527 if ($disp) {
528 $disp .= "AND {$params['external_identifier']}";
529 }
530 else {
531 $disp = $params['external_identifier'];
532 }
533 }
534
535 array_unshift($values, 'No matching Contact found for (' . $disp . ')');
536 return CRM_Import_Parser::ERROR;
537 }
538 }
539 else {
540 if (!empty($paramValues['external_identifier'])) {
541 $checkCid = new CRM_Contact_DAO_Contact();
542 $checkCid->external_identifier = $paramValues['external_identifier'];
543 $checkCid->find(TRUE);
544 if ($checkCid->id != $formatted['contact_id']) {
545 array_unshift($values, 'Mismatch of External identifier :' . $paramValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id']);
546 return CRM_Import_Parser::ERROR;
547 }
548 }
549 $newContribution = civicrm_api('contribution', 'create', $formatted);
550 if (civicrm_error($newContribution)) {
551 if (is_array($newContribution['error_message'])) {
552 array_unshift($values, $newContribution['error_message']['message']);
553 if ($newContribution['error_message']['params'][0]) {
554 return CRM_Import_Parser::DUPLICATE;
555 }
556 }
557 else {
558 array_unshift($values, $newContribution['error_message']);
559 return CRM_Import_Parser::ERROR;
560 }
561 }
562
563 $this->_newContributions[] = $newContribution['id'];
564 $formatted['contribution_id'] = $newContribution['id'];
565
566 //return soft valid since we need to show how soft credits were added
567 if (!empty($formatted['soft_credit'])) {
568 return CRM_Contribute_Import_Parser::SOFT_CREDIT;
569 }
570
571 // process pledge payment assoc w/ the contribution
572 return self::processPledgePayments($formatted);
573
574 return CRM_Import_Parser::VALID;
575 }
576 }
577
578 /**
579 * Process pledge payments.
580 *
581 * @param array $formatted
582 *
583 * @return int
584 */
585 public function processPledgePayments(&$formatted) {
586 if (!empty($formatted['pledge_payment_id']) && !empty($formatted['pledge_id'])) {
587 //get completed status
588 $completeStatusID = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
589
590 //need to update payment record to map contribution_id
591 CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_PledgePayment', $formatted['pledge_payment_id'],
592 'contribution_id', $formatted['contribution_id']
593 );
594
595 CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($formatted['pledge_id'],
596 array($formatted['pledge_payment_id']),
597 $completeStatusID,
598 NULL,
599 $formatted['total_amount']
600 );
601
602 return CRM_Contribute_Import_Parser::PLEDGE_PAYMENT;
603 }
604 }
605
606 /**
607 * Get the array of successfully imported contribution id's
608 *
609 * @return array
610 */
611 public function &getImportedContributions() {
612 return $this->_newContributions;
613 }
614
615 /**
616 * The initializer code, called before the processing
617 *
618 * @return void
619 */
620 public function fini() {
621 }
622
623 }