3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2015
37 * Class to parse contribution csv files.
39 class CRM_Contribute_Import_Parser_Contribution
extends CRM_Contribute_Import_Parser
{
41 protected $_mapperKeys;
43 private $_contactIdIndex;
44 private $_totalAmountIndex;
45 private $_contributionTypeIndex;
47 protected $_mapperSoftCredit;
48 //protected $_mapperPhoneType;
51 * Array of successfully imported contribution id's
55 protected $_newContributions;
61 * @param null $mapperSoftCredit
62 * @param null $mapperPhoneType
63 * @param null $mapperSoftCreditType
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;
73 * The initializer code, called before the processing
77 public function init() {
78 $fields = CRM_Contribute_BAO_Contribution
::importableFields($this->_contactType
, FALSE);
80 $fields = array_merge($fields,
82 'soft_credit' => array(
83 'title' => ts('Soft Credit'),
85 'headerPattern' => '/Soft Credit/i',
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',
98 'title' => ts('Pledge ID'),
99 'headerPattern' => '/Pledge ID/i',
103 $fields = array_merge($fields, $pledgeFields);
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']);
112 $this->_newContributions
= array();
114 $this->setActiveFields($this->_mapperKeys
);
115 $this->setActiveFieldSoftCredit($this->_mapperSoftCredit
);
116 $this->setActiveFieldSoftCreditType($this->_mapperSoftCreditType
);
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;
124 foreach ($this->_mapperKeys
as $key) {
126 case 'contribution_contact_id':
127 $this->_contactIdIndex
= $index;
131 $this->_totalAmountIndex
= $index;
134 case 'financial_type':
135 $this->_contributionTypeIndex
= $index;
143 * Handle the values in mapField mode.
145 * @param array $values
146 * The array of values belonging to this line.
150 public function mapField(&$values) {
151 return CRM_Import_Parser
::VALID
;
155 * Handle the values in preview mode.
157 * @param array $values
158 * The array of values belonging to this line.
161 * the result of this processing
163 public function preview(&$values) {
164 return $this->summary($values);
168 * Handle the values in summary mode.
170 * @param array $values
171 * The array of values belonging to this line.
174 * the result of this processing
176 public function summary(&$values) {
177 $erroneousField = NULL;
178 $response = $this->setActiveFieldValues($values, $erroneousField);
180 $params = &$this->getActiveFieldParams();
181 $errorMessage = NULL;
184 $session = CRM_Core_Session
::singleton();
185 $dateType = $session->get('dateTypes');
186 foreach ($params as $key => $val) {
190 if ($dateValue = CRM_Utils_Date
::formatDate($params[$key], $dateType)) {
191 $params[$key] = $dateValue;
194 CRM_Contact_Import_Parser_Contact
::addToErrorMsg('Receive Date', $errorMessage);
199 if ($dateValue = CRM_Utils_Date
::formatDate($params[$key], $dateType)) {
200 $params[$key] = $dateValue;
203 CRM_Contact_Import_Parser_Contact
::addToErrorMsg('Cancel Date', $errorMessage);
208 if ($dateValue = CRM_Utils_Date
::formatDate($params[$key], $dateType)) {
209 $params[$key] = $dateValue;
212 CRM_Contact_Import_Parser_Contact
::addToErrorMsg('Receipt date', $errorMessage);
216 case 'thankyou_date':
217 if ($dateValue = CRM_Utils_Date
::formatDate($params[$key], $dateType)) {
218 $params[$key] = $dateValue;
221 CRM_Contact_Import_Parser_Contact
::addToErrorMsg('Thankyou Date', $errorMessage);
227 //date-Format part ends
229 $params['contact_type'] = 'Contribution';
231 //checking error in custom data
232 CRM_Contact_Import_Parser_Contact
::isErrorInCustomData($params, $errorMessage);
235 $tempMsg = "Invalid value for field(s) : $errorMessage";
236 array_unshift($values, $tempMsg);
237 $errorMessage = NULL;
238 return CRM_Import_Parser
::ERROR
;
241 return CRM_Import_Parser
::VALID
;
245 * Handle the values in import mode.
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.
253 * the result of this processing
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
) {
262 $params = &$this->getActiveFieldParams();
263 $params['contact_type'] = 'Contribution';
264 $formatted = array('version' => 3);
266 // don't add to recent items, CRM-4399
267 $formatted['skipRecentView'] = TRUE;
270 $session = CRM_Core_Session
::singleton();
271 $dateType = $session->get('dateTypes');
273 $customFields = CRM_Core_BAO_CustomField
::getFields(CRM_Utils_Array
::value('contact_type', $params));
276 if (isset($params['total_amount']) && $params['total_amount'] == 0) {
277 $params['total_amount'] = '0.00';
279 foreach ($params as $key => $val) {
285 case 'thankyou_date':
286 $params[$key] = CRM_Utils_Date
::formatDate($params[$key], $dateType);
289 case 'pledge_payment':
290 $params[$key] = CRM_Utils_String
::strtobool($val);
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]);
299 elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') {
300 $params[$key] = CRM_Utils_String
::strtoboolstr($val);
305 //date-Format part ends
307 static $indieFields = NULL;
308 if ($indieFields == NULL) {
309 $tempIndieFields = CRM_Contribute_DAO_Contribution
::import();
310 $indieFields = $tempIndieFields;
313 $paramValues = array();
314 foreach ($params as $key => $field) {
315 if ($field == NULL ||
$field === '') {
318 $paramValues[$key] = $field;
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']))
325 $paramValues['contact_type'] = $this->_contactType
;
327 elseif ($onDuplicate == CRM_Import_Parser
::DUPLICATE_UPDATE
&&
328 (!empty($paramValues['contribution_id']) ||
!empty($values['trxn_id']) ||
!empty($paramValues['invoice_id']))
330 $paramValues['contact_type'] = $this->_contactType
;
332 elseif (!empty($params['soft_credit'])) {
333 $paramValues['contact_type'] = $this->_contactType
;
335 elseif (!empty($paramValues['pledge_payment'])) {
336 $paramValues['contact_type'] = $this->_contactType
;
339 //need to pass $onDuplicate to check import mode.
340 if (!empty($paramValues['pledge_payment'])) {
341 $paramValues['onDuplicate'] = $onDuplicate;
343 require_once 'CRM/Utils/DeprecatedUtils.php';
344 $formatError = _civicrm_api3_deprecated_formatted_param($paramValues, $formatted, TRUE, $onDuplicate);
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
;
351 elseif (CRM_Utils_Array
::value('error_data', $formatError) == 'pledge_payment') {
352 return CRM_Contribute_Import_Parser
::PLEDGE_PAYMENT_ERROR
;
354 return CRM_Import_Parser
::ERROR
;
357 if ($onDuplicate != CRM_Import_Parser
::DUPLICATE_UPDATE
) {
358 $formatted['custom'] = CRM_Core_BAO_CustomField
::postProcess($formatted,
364 //fix for CRM-2219 - Update Contribution
365 // onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE
366 if (!empty($paramValues['invoice_id']) ||
!empty($paramValues['trxn_id']) ||
!empty($paramValues['contribution_id'])) {
368 'id' => CRM_Utils_Array
::value('contribution_id', $paramValues),
369 'trxn_id' => CRM_Utils_Array
::value('trxn_id', $paramValues),
370 'invoice_id' => CRM_Utils_Array
::value('invoice_id', $paramValues),
373 $ids['contribution'] = CRM_Contribute_BAO_Contribution
::checkDuplicateIds($dupeIds);
375 if ($ids['contribution']) {
376 $formatted['id'] = $ids['contribution'];
377 $formatted['custom'] = CRM_Core_BAO_CustomField
::postProcess($formatted,
382 if (!empty($paramValues['note'])) {
384 $contactID = CRM_Core_DAO
::getFieldValue('CRM_Contribute_DAO_Contribution', $ids['contribution'], 'contact_id');
385 $daoNote = new CRM_Core_BAO_Note();
386 $daoNote->entity_table
= 'civicrm_contribution';
387 $daoNote->entity_id
= $ids['contribution'];
388 if ($daoNote->find(TRUE)) {
389 $noteID['id'] = $daoNote->id
;
393 'entity_table' => 'civicrm_contribution',
394 'note' => $paramValues['note'],
395 'entity_id' => $ids['contribution'],
396 'contact_id' => $contactID,
398 CRM_Core_BAO_Note
::add($noteParams, $noteID);
399 unset($formatted['note']);
402 //need to check existing soft credit contribution, CRM-3968
403 if (!empty($formatted['soft_credit'])) {
404 $dupeSoftCredit = array(
405 'contact_id' => $formatted['soft_credit'],
406 'contribution_id' => $ids['contribution'],
409 //Delete all existing soft Contribution from contribution_soft table for pcp_id is_null
410 $existingSoftCredit = CRM_Contribute_BAO_ContributionSoft
::getSoftContribution($dupeSoftCredit['contribution_id']);
411 if (isset($existingSoftCredit['soft_credit']) && !empty($existingSoftCredit['soft_credit'])) {
412 foreach ($existingSoftCredit['soft_credit'] as $key => $existingSoftCreditValues) {
413 if (!empty($existingSoftCreditValues['soft_credit_id'])) {
414 $deleteParams = array(
415 'id' => $existingSoftCreditValues['soft_credit_id'],
418 CRM_Contribute_BAO_ContributionSoft
::del($deleteParams);
424 $newContribution = CRM_Contribute_BAO_Contribution
::create($formatted, $ids);
425 $this->_newContributions
[] = $newContribution->id
;
427 //return soft valid since we need to show how soft credits were added
428 if (!empty($formatted['soft_credit'])) {
429 return CRM_Contribute_Import_Parser
::SOFT_CREDIT
;
432 // process pledge payment assoc w/ the contribution
433 return self
::processPledgePayments($formatted);
435 return CRM_Import_Parser
::VALID
;
439 'id' => 'Contribution ID',
440 'trxn_id' => 'Transaction ID',
441 'invoice_id' => 'Invoice ID',
443 foreach ($dupeIds as $k => $v) {
445 $errorMsg[] = "$labels[$k] $v";
448 $errorMsg = implode(' AND ', $errorMsg);
449 array_unshift($values, 'Matching Contribution record not found for ' . $errorMsg . '. Row was skipped.');
450 return CRM_Import_Parser
::ERROR
;
455 if ($this->_contactIdIndex
< 0) {
456 // set the contact type if its not set
457 if (!isset($paramValues['contact_type'])) {
458 $paramValues['contact_type'] = $this->_contactType
;
461 $paramValues['version'] = 3;
462 //retrieve contact id using contact dedupe rule
463 require_once 'CRM/Utils/DeprecatedUtils.php';
464 $error = _civicrm_api3_deprecated_check_contact_dedupe($paramValues);
466 if (CRM_Core_Error
::isAPIError($error, CRM_Core_ERROR
::DUPLICATE_CONTACT
)) {
467 $matchedIDs = explode(',', $error['error_message']['params'][0]);
468 if (count($matchedIDs) > 1) {
469 array_unshift($values, 'Multiple matching contact records detected for this row. The contribution was not imported');
470 return CRM_Import_Parser
::ERROR
;
473 $cid = $matchedIDs[0];
474 $formatted['contact_id'] = $cid;
476 $newContribution = civicrm_api('contribution', 'create', $formatted);
477 if (civicrm_error($newContribution)) {
478 if (is_array($newContribution['error_message'])) {
479 array_unshift($values, $newContribution['error_message']['message']);
480 if ($newContribution['error_message']['params'][0]) {
481 return CRM_Import_Parser
::DUPLICATE
;
485 array_unshift($values, $newContribution['error_message']);
486 return CRM_Import_Parser
::ERROR
;
490 $this->_newContributions
[] = $newContribution['id'];
491 $formatted['contribution_id'] = $newContribution['id'];
493 //return soft valid since we need to show how soft credits were added
494 if (!empty($formatted['soft_credit'])) {
495 return CRM_Contribute_Import_Parser
::SOFT_CREDIT
;
498 // process pledge payment assoc w/ the contribution
499 return self
::processPledgePayments($formatted);
501 return CRM_Import_Parser
::VALID
;
505 // Using new Dedupe rule.
507 'contact_type' => $this->_contactType
,
508 'used' => 'Unsupervised',
510 $fieldsArray = CRM_Dedupe_BAO_Rule
::dedupeRuleFields($ruleParams);
512 foreach ($fieldsArray as $value) {
513 if (array_key_exists(trim($value), $params)) {
514 $paramValue = $params[trim($value)];
515 if (is_array($paramValue)) {
516 $disp .= $params[trim($value)][0][trim($value)] . " ";
519 $disp .= $params[trim($value)] . " ";
524 if (!empty($params['external_identifier'])) {
526 $disp .= "AND {$params['external_identifier']}";
529 $disp = $params['external_identifier'];
533 array_unshift($values, 'No matching Contact found for (' . $disp . ')');
534 return CRM_Import_Parser
::ERROR
;
538 if (!empty($paramValues['external_identifier'])) {
539 $checkCid = new CRM_Contact_DAO_Contact();
540 $checkCid->external_identifier
= $paramValues['external_identifier'];
541 $checkCid->find(TRUE);
542 if ($checkCid->id
!= $formatted['contact_id']) {
543 array_unshift($values, 'Mismatch of External identifier :' . $paramValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id']);
544 return CRM_Import_Parser
::ERROR
;
547 $newContribution = civicrm_api('contribution', 'create', $formatted);
548 if (civicrm_error($newContribution)) {
549 if (is_array($newContribution['error_message'])) {
550 array_unshift($values, $newContribution['error_message']['message']);
551 if ($newContribution['error_message']['params'][0]) {
552 return CRM_Import_Parser
::DUPLICATE
;
556 array_unshift($values, $newContribution['error_message']);
557 return CRM_Import_Parser
::ERROR
;
561 $this->_newContributions
[] = $newContribution['id'];
562 $formatted['contribution_id'] = $newContribution['id'];
564 //return soft valid since we need to show how soft credits were added
565 if (!empty($formatted['soft_credit'])) {
566 return CRM_Contribute_Import_Parser
::SOFT_CREDIT
;
569 // process pledge payment assoc w/ the contribution
570 return self
::processPledgePayments($formatted);
572 return CRM_Import_Parser
::VALID
;
577 * Process pledge payments.
579 * @param array $formatted
583 public function processPledgePayments(&$formatted) {
584 if (!empty($formatted['pledge_payment_id']) && !empty($formatted['pledge_id'])) {
585 //get completed status
586 $completeStatusID = CRM_Core_OptionGroup
::getValue('contribution_status', 'Completed', 'name');
588 //need to update payment record to map contribution_id
589 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', $formatted['pledge_payment_id'],
590 'contribution_id', $formatted['contribution_id']
593 CRM_Pledge_BAO_PledgePayment
::updatePledgePaymentStatus($formatted['pledge_id'],
594 array($formatted['pledge_payment_id']),
597 $formatted['total_amount']
600 return CRM_Contribute_Import_Parser
::PLEDGE_PAYMENT
;
605 * Get the array of successfully imported contribution id's
609 public function &getImportedContributions() {
610 return $this->_newContributions
;
614 * The initializer code, called before the processing
618 public function fini() {