From 01c21f7ee60ccf446c4095bf6273a37cd56f9a88 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Thu, 26 May 2022 12:37:29 +1200 Subject: [PATCH] Simplify handling of soft credit --- CRM/Contribute/BAO/Contribution.php | 2 +- CRM/Contribute/Import/Form/MapField.php | 7 +- CRM/Contribute/Import/Form/Preview.php | 21 +- CRM/Contribute/Import/Parser/Contribution.php | 254 +++++++----------- CRM/Import/Parser.php | 4 +- .../Import/Parser/ContributionTest.php | 75 +++++- 6 files changed, 168 insertions(+), 195 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index 29d6fc1ba6..800c28ac94 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -753,7 +753,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution im $tmpContactField['external_identifier'] = $contactFields['external_identifier']; $tmpContactField['external_identifier']['title'] = $contactFields['external_identifier']['title'] . ' ' . ts('(match to contact)'); - $tmpFields['contribution_contact_id']['title'] = $tmpFields['contribution_contact_id']['title'] . ' ' . ts('(match to contact)'); + $tmpFields['contribution_contact_id']['title'] = $tmpFields['contribution_contact_id']['html']['label'] = $tmpFields['contribution_contact_id']['title'] . ' ' . ts('(match to contact)'); $fields = array_merge($fields, $tmpContactField); $fields = array_merge($fields, $tmpFields); $fields = array_merge($fields, $note); diff --git a/CRM/Contribute/Import/Form/MapField.php b/CRM/Contribute/Import/Form/MapField.php index 61db6eaa4d..78e6a869d8 100644 --- a/CRM/Contribute/Import/Form/MapField.php +++ b/CRM/Contribute/Import/Form/MapField.php @@ -166,7 +166,6 @@ class CRM_Contribute_Import_Form_MapField extends CRM_Import_Form_MapField { foreach ($mapperKeys as $key) { $this->_fieldUsed[$key] = FALSE; } - $this->_location_types = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'); $sel1 = $this->_mapperFields; if (!$this->get('onDuplicate')) { @@ -420,8 +419,9 @@ class CRM_Contribute_Import_Form_MapField extends CRM_Import_Form_MapField { $this->controller->resetPage($this->_name); return; } + $this->updateUserJobMetadata('submitted_values', $this->getSubmittedValues()); - $mapper = $mapperKeys = $mapperKeysMain = $mapperSoftCredit = $softCreditFields = $mapperPhoneType = $mapperSoftCreditType = []; + $mapper = $mapperKeysMain = $mapperSoftCredit = $softCreditFields = $mapperPhoneType = $mapperSoftCreditType = []; $mapperKeys = $this->controller->exportValue($this->_name, 'mapper'); $softCreditTypes = CRM_Core_OptionGroup::values('soft_credit_type'); @@ -478,7 +478,8 @@ class CRM_Contribute_Import_Form_MapField extends CRM_Import_Form_MapField { $this->set('savedMapping', $saveMapping->id); } - $parser = new CRM_Contribute_Import_Parser_Contribution($mapperKeysMain, $mapperSoftCredit, $mapperPhoneType); + $parser = new CRM_Contribute_Import_Parser_Contribution($mapperKeysMain); + $parser->setUserJobID($this->getUserJobID()); $parser->run( $this->getSubmittedValue('uploadFile'), $this->getSubmittedValue('fieldSeparator'), diff --git a/CRM/Contribute/Import/Form/Preview.php b/CRM/Contribute/Import/Form/Preview.php index f496b167b9..6d2927bcf2 100644 --- a/CRM/Contribute/Import/Form/Preview.php +++ b/CRM/Contribute/Import/Form/Preview.php @@ -69,28 +69,13 @@ class CRM_Contribute_Import_Form_Preview extends CRM_Import_Form_Preview { */ public function postProcess() { $fileName = $this->controller->exportValue('DataSource', 'uploadFile'); - $invalidRowCount = $this->get('invalidRowCount'); $onDuplicate = $this->get('onDuplicate'); - $mapperSoftCreditType = $this->get('mapperSoftCreditType'); - + $this->updateUserJobMetadata('submitted_values', $this->getSubmittedValues()); $mapper = $this->controller->exportValue('MapField', 'mapper'); - $mapperKeys = []; - $mapperSoftCredit = []; - $mapperPhoneType = []; - foreach ($mapper as $key => $value) { - $mapperKeys[$key] = $mapper[$key][0]; - if (isset($mapper[$key][0]) && $mapper[$key][0] == 'soft_credit' && isset($mapper[$key])) { - $mapperSoftCredit[$key] = $mapper[$key][1] ?? ''; - $mapperSoftCreditType[$key] = $mapperSoftCreditType[$key]['value']; - } - else { - $mapperSoftCredit[$key] = $mapperSoftCreditType[$key] = NULL; - } - } - - $parser = new CRM_Contribute_Import_Parser_Contribution($mapperKeys, $mapperSoftCredit, $mapperPhoneType, $mapperSoftCreditType); + $parser = new CRM_Contribute_Import_Parser_Contribution(); $parser->setUserJobID($this->getUserJobID()); + $mapFields = $this->get('fields'); foreach ($mapper as $key => $value) { diff --git a/CRM/Contribute/Import/Parser/Contribution.php b/CRM/Contribute/Import/Parser/Contribution.php index 0daba3335e..22ade85dd4 100644 --- a/CRM/Contribute/Import/Parser/Contribution.php +++ b/CRM/Contribute/Import/Parser/Contribution.php @@ -15,6 +15,9 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ +use Civi\Api4\Contact; +use Civi\Api4\Email; + /** * Class to parse contribution csv files. */ @@ -22,11 +25,6 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { protected $_mapperKeys; - private $_contactIdIndex; - - protected $_mapperSoftCredit; - //protected $_mapperPhoneType; - /** * Array of successfully imported contribution id's * @@ -38,15 +36,10 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { * Class constructor. * * @param $mapperKeys - * @param array $mapperSoftCredit - * @param null $mapperPhoneType - * @param array $mapperSoftCreditType */ - public function __construct(&$mapperKeys = [], $mapperSoftCredit = [], $mapperPhoneType = NULL, $mapperSoftCreditType = []) { + public function __construct($mapperKeys = []) { parent::__construct(); - $this->_mapperKeys = &$mapperKeys; - $this->_mapperSoftCredit = &$mapperSoftCredit; - $this->_mapperSoftCreditType = &$mapperSoftCreditType; + $this->_mapperKeys = $mapperKeys; } /** @@ -164,19 +157,9 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { throw new CRM_Core_Exception('Unable to determine import file'); } $fileName = $fileName['name']; - - switch ($contactType) { - case self::CONTACT_INDIVIDUAL: - $this->_contactType = 'Individual'; - break; - - case self::CONTACT_HOUSEHOLD: - $this->_contactType = 'Household'; - break; - - case self::CONTACT_ORGANIZATION: - $this->_contactType = 'Organization'; - } + // Since $this->_contactType is still being called directly do a get call + // here to make sure it is instantiated. + $this->getContactType(); $this->init(); @@ -405,65 +388,24 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { } /** - * Store the soft credit field information. - * - * This was perhaps done this way on the believe that a lot of code pain - * was worth it to avoid negligible-cost array iterations. Perhaps we could prioritise - * readability & maintainability next since we can just work with functions to retrieve - * data from the metadata. + * Get the field mappings for the import. * - * @param array $elements - */ - public function setActiveFieldSoftCredit($elements) { - foreach ((array) $elements as $i => $element) { - $this->_activeFields[$i]->_softCreditField = $element; - } - } - - /** - * Store the soft credit field type information. - * - * This was perhaps done this way on the believe that a lot of code pain - * was worth it to avoid negligible-cost array iterations. Perhaps we could prioritise - * readability & maintainability next since we can just work with functions to retrieve - * data from the metadata. - * - * @param array $elements - */ - public function setActiveFieldSoftCreditType($elements) { - foreach ((array) $elements as $i => $element) { - $this->_activeFields[$i]->_softCreditType = $element; - } - } - - /** - * Format the field values for input to the api. + * This is the same format as saved in civicrm_mapping_field except + * that location_type_id = 'Primary' rather than empty where relevant. + * Also 'im_provider_id' is mapped to the 'real' field name 'provider_id' * * @return array - * (reference ) associative array of name/value pairs + * @throws \API_Exception */ - public function &getActiveFieldParams() { - $params = []; - for ($i = 0; $i < $this->_activeFieldCount; $i++) { - if (isset($this->_activeFields[$i]->_value)) { - if (isset($this->_activeFields[$i]->_softCreditField)) { - if (!isset($params[$this->_activeFields[$i]->_name])) { - $params[$this->_activeFields[$i]->_name] = []; - } - $params[$this->_activeFields[$i]->_name][$i][$this->_activeFields[$i]->_softCreditField] = $this->_activeFields[$i]->_value; - if (isset($this->_activeFields[$i]->_softCreditType)) { - $params[$this->_activeFields[$i]->_name][$i]['soft_credit_type_id'] = $this->_activeFields[$i]->_softCreditType; - } - } - - if (!isset($params[$this->_activeFields[$i]->_name])) { - if (!isset($this->_activeFields[$i]->_softCreditField)) { - $params[$this->_activeFields[$i]->_name] = $this->_activeFields[$i]->_value; - } - } - } + protected function getFieldMappings(): array { + $mappedFields = []; + foreach ($this->getSubmittedValue('mapper') as $i => $mapperRow) { + $mappedField = $this->getMappingFieldFromMapperInput($mapperRow, 0, $i); + // Just for clarity since 0 is a pseudo-value + unset($mappedField['mapping_id']); + $mappedFields[] = $mappedField; } - return $params; + return $mappedFields; } /** @@ -695,22 +637,6 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { $this->_newContributions = []; $this->setActiveFields($this->_mapperKeys); - $this->setActiveFieldSoftCredit($this->_mapperSoftCredit); - $this->setActiveFieldSoftCreditType($this->_mapperSoftCreditType); - - // FIXME: we should do this in one place together with Form/MapField.php - $this->_contactIdIndex = -1; - - $index = 0; - foreach ($this->_mapperKeys as $key) { - switch ($key) { - case 'contribution_contact_id': - $this->_contactIdIndex = $index; - break; - - } - $index++; - } } /** @@ -766,9 +692,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { * CRM_Import_Parser::VALID or CRM_Import_Parser::ERROR */ public function summary(&$values) { - $this->setActiveFieldValues($values); - - $params = $this->getActiveFieldParams(); + $params = $this->getMappedRow($values); //for date-Formats $errorMessage = implode('; ', $this->formatDateFields($params)); @@ -814,7 +738,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { return CRM_Import_Parser::ERROR; } - $params = &$this->getActiveFieldParams(); + $params = $this->getMappedRow($values); $formatted = ['version' => 3, 'skipRecentView' => TRUE, 'skipCleanMoney' => FALSE]; //CRM-10994 @@ -842,9 +766,6 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { ) { $paramValues['contact_type'] = $this->_contactType; } - elseif (!empty($params['soft_credit'])) { - $paramValues['contact_type'] = $this->_contactType; - } elseif (!empty($paramValues['pledge_payment'])) { $paramValues['contact_type'] = $this->_contactType; } @@ -853,7 +774,14 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { if (!empty($paramValues['pledge_payment'])) { $paramValues['onDuplicate'] = $onDuplicate; } - $formatError = $this->deprecatedFormatParams($paramValues, $formatted, TRUE, $onDuplicate); + try { + $formatError = $this->deprecatedFormatParams($paramValues, $formatted, TRUE, $onDuplicate); + } + catch (CRM_Core_Exception $e) { + array_unshift($values, $e->getMessage()); + $errorMapping = ['soft_credit' => self::SOFT_CREDIT_ERROR, 'pledge_payment' => self::PLEDGE_PAYMENT_ERROR]; + return $errorMapping[$e->getErrorCode()] ?? CRM_Import_Parser::ERROR; + } if ($formatError) { array_unshift($values, $formatError['error_message']); @@ -950,7 +878,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { } } - if ($this->_contactIdIndex < 0) { + if (empty($formatted['contact_id'])) { $error = $this->checkContactDuplicate($paramValues); @@ -1208,6 +1136,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { * @param int $onDuplicate * * @return array|CRM_Error + * @throws \CRM_Core_Exception */ private function deprecatedFormatParams($params, &$values, $create = FALSE, $onDuplicate = NULL) { require_once 'CRM/Utils/DeprecatedUtils.php'; @@ -1252,7 +1181,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { } switch ($key) { - case 'contribution_contact_id': + case 'contact_id': if (!CRM_Utils_Rule::integer($value)) { return civicrm_api3_create_error("contact_id not valid: $value"); } @@ -1267,9 +1196,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { elseif ($svq == 1) { return civicrm_api3_create_error("Invalid Contact ID: contact_id $value is a soft-deleted contact."); } - - $values['contact_id'] = $values['contribution_contact_id']; - unset($values['contribution_contact_id']); + $values['contact_id'] = $value; break; case 'contact_type': @@ -1369,58 +1296,11 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { case 'soft_credit': // import contribution record according to select contact type // validate contact id and external identifier. - $value[$key] = $mismatchContactType = $softCreditContactIds = ''; - if (isset($params[$key]) && is_array($params[$key])) { - foreach ($params[$key] as $softKey => $softParam) { - $contactId = $softParam['contact_id'] ?? NULL; - $externalId = $softParam['external_identifier'] ?? NULL; - $email = $softParam['email'] ?? NULL; - if ($contactId || $externalId) { - require_once 'CRM/Contact/DAO/Contact.php'; - $contact = new CRM_Contact_DAO_Contact(); - $contact->id = $contactId; - $contact->external_identifier = $externalId; - $errorMsg = NULL; - if (!$contact->find(TRUE)) { - $field = $contactId ? ts('Contact ID') : ts('External ID'); - $errorMsg = ts("Soft Credit %1 - %2 doesn't exist. Row was skipped.", - [1 => $field, 2 => $contactId ? $contactId : $externalId]); - } - - if ($errorMsg) { - return civicrm_api3_create_error($errorMsg); - } - - // finally get soft credit contact id. - $values[$key][$softKey] = $softParam; - $values[$key][$softKey]['contact_id'] = $contact->id; - } - elseif ($email) { - if (!CRM_Utils_Rule::email($email)) { - return civicrm_api3_create_error("Invalid email address $email provided for Soft Credit. Row was skipped"); - } - - // get the contact id from duplicate contact rule, if more than one contact is returned - // we should return error, since current interface allows only one-one mapping - $emailParams = [ - 'email' => $email, - 'contact_type' => $params['contact_type'], - ]; - $checkDedupe = _civicrm_api3_deprecated_duplicate_formatted_contact($emailParams); - if (!$checkDedupe['is_error']) { - return civicrm_api3_create_error("Invalid email address(doesn't exist) $email for Soft Credit. Row was skipped"); - } - $matchingContactIds = explode(',', $checkDedupe['error_message']['params'][0]); - if (count($matchingContactIds) > 1) { - return civicrm_api3_create_error("Invalid email address(duplicate) $email for Soft Credit. Row was skipped"); - } - if (count($matchingContactIds) == 1) { - $contactId = $matchingContactIds[0]; - unset($softParam['email']); - $values[$key][$softKey] = $softParam + ['contact_id' => $contactId]; - } - } - } + foreach ($value as $softKey => $softParam) { + $values['soft_credit'][$softKey] = [ + 'contact_id' => $this->lookupMatchingContact($softParam), + 'soft_credit_type_id' => $softParam['soft_credit_type_id'], + ]; } break; @@ -1593,8 +1473,6 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { * @throws \API_Exception */ public function getMappingFieldFromMapperInput(array $fieldMapping, int $mappingID, int $columnNumber): array { - $isRelationshipField = preg_match('/\d*_a_b|b_a$/', $fieldMapping[0]); - $fieldName = $isRelationshipField ? $fieldMapping[1] : $fieldMapping[0]; return [ 'name' => $fieldMapping[0], 'mapping_id' => $mappingID, @@ -1609,4 +1487,56 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser { ]; } + /** + * Lookup matching contact. + * + * This looks up the matching contact from the contact id, external identifier + * or email. For the email a straight email search is done - this is equivalent + * to what happens on a dedupe rule lookup when the only field is 'email' - but + * we can't be sure the rule is 'just email' - and we are not collecting the + * fields for any other lookup in the case of soft credits (if we + * extend this function to main-contact-lookup we can handle full dedupe + * lookups - but note the error messages will need tweaking. + * + * @param array $params + * + * @return int + * Contact ID + * + * @throws \API_Exception + * @throws \CRM_Core_Exception + */ + private function lookupMatchingContact(array $params): int { + $lookupField = !empty($params['contact_id']) ? 'contact_id' : (!empty($params['external_identifier']) ? 'external_identifier' : 'email'); + if (empty($params['email'])) { + $contact = Contact::get(FALSE)->addSelect('id') + ->addWhere($lookupField, '=', $params[$lookupField]) + ->execute(); + if (count($contact) !== 1) { + throw new CRM_Core_Exception(ts("Soft Credit %1 - %2 doesn't exist. Row was skipped.", + [ + 1 => $this->getFieldMetadata($lookupField), + 2 => $params['contact_id'] ?? $params['external_identifier'], + ])); + } + return $contact->first()['id']; + } + + if (!CRM_Utils_Rule::email($params['email'])) { + throw new CRM_Core_Exception(ts('Invalid email address %1 provided for Soft Credit. Row was skipped'), [1 => $params['email']]); + } + $emails = Email::get(FALSE) + ->addWhere('contact_id.is_deleted', '=', 0) + ->addWhere('contact_id.contact_type', '=', $this->getContactType()) + ->addWhere('email', '=', $params['email']) + ->addSelect('contact_id')->execute(); + if (count($emails) === 0) { + throw new CRM_Core_Exception(ts("Invalid email address(doesn't exist) %1 for Soft Credit. Row was skipped", [1 => $params['email']])); + } + if (count($emails) > 1) { + throw new CRM_Core_Exception(ts('Invalid email address(duplicate) %1 for Soft Credit. Row was skipped', [1 => $params['email']])); + } + return $emails->first()['contact_id']; + } + } diff --git a/CRM/Import/Parser.php b/CRM/Import/Parser.php index 4ea35b98c4..bf05a50135 100644 --- a/CRM/Import/Parser.php +++ b/CRM/Import/Parser.php @@ -694,7 +694,7 @@ abstract class CRM_Import_Parser { */ protected function checkContactDuplicate(&$formatValues) { //retrieve contact id using contact dedupe rule - $formatValues['contact_type'] = $formatValues['contact_type'] ?? $this->_contactType; + $formatValues['contact_type'] = $formatValues['contact_type'] ?? $this->getContactType(); $formatValues['version'] = 3; require_once 'CRM/Utils/DeprecatedUtils.php'; $params = $formatValues; @@ -723,7 +723,7 @@ abstract class CRM_Import_Parser { } // CRM-17040, Considering only primary contact when importing contributions. So contribution inserts into primary contact // instead of soft credit contact. - if (is_array($field) && $key != "soft_credit") { + if (is_array($field) && $key !== "soft_credit") { foreach ($field as $value) { $break = FALSE; if (is_array($value)) { diff --git a/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php b/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php index d360352225..7fabd10ac6 100644 --- a/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php +++ b/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php @@ -7,6 +7,7 @@ use Civi\Api4\Contribution; use Civi\Api4\ContributionSoft; use Civi\Api4\OptionValue; +use Civi\Api4\UserJob; /** * Test Contribution import parser. @@ -68,9 +69,13 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase { 'external_identifier' => 'ext-1', 'soft_credit' => 'ext-2', ]; - $mapperSoftCredit = [NULL, NULL, NULL, 'external_identifier']; - $mapperSoftCreditType = [NULL, NULL, NULL, '1']; - $this->runImport($values, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Contribute_Import_Parser_Contribution::SOFT_CREDIT, $mapperSoftCredit, NULL, $mapperSoftCreditType); + $mapping = [ + ['name' => 'total_amount'], + ['name' => 'financial_type_id'], + ['name' => 'external_identifier'], + ['name' => 'soft_credit', 'soft_credit_type_id' => 1, 'soft_credit_match_field' => 'external_identifier'], + ]; + $this->runImport($values, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Contribute_Import_Parser_Contribution::SOFT_CREDIT, $mapping); $contributionsOfMainContact = Contribution::get()->addWhere('contact_id', '=', $contact1Id)->execute(); $this->assertCount(1, $contributionsOfMainContact, 'Contribution not added for primary contact'); @@ -251,23 +256,75 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase { * * @param int $onDuplicateAction * @param int|null $expectedResult - * @param array|null $mapperSoftCredit - * @param array|null $mapperPhoneType - * @param array|null $mapperSoftCreditType + * @param array|null $mappings * @param array|null $fields * Array of field names. Will be calculated from $originalValues if not passed in. */ - protected function runImport(array $originalValues, int $onDuplicateAction, ?int $expectedResult, array $mapperSoftCredit = NULL, array $mapperPhoneType = NULL, array $mapperSoftCreditType = NULL, array $fields = NULL): void { + protected function runImport(array $originalValues, int $onDuplicateAction, ?int $expectedResult, array $mappings = [], array $fields = NULL): void { if (!$fields) { $fields = array_keys($originalValues); } + $mapper = []; + if ($mappings) { + foreach ($mappings as $mapping) { + $fieldInput = [$mapping['name']]; + if (!empty($mapping['soft_credit_type_id'])) { + $fieldInput[1] = $mapping['soft_credit_match_field']; + $fieldInput[2] = $mapping['soft_credit_type_id']; + } + $mapper[] = $fieldInput; + } + } + else { + foreach ($fields as $field) { + $mapper[] = [$field]; + } + } $values = array_values($originalValues); - $parser = new CRM_Contribute_Import_Parser_Contribution($fields, $mapperSoftCredit, $mapperPhoneType, $mapperSoftCreditType); - $parser->_contactType = 'Individual'; + $parser = new CRM_Contribute_Import_Parser_Contribution($fields); + $parser->setUserJobID($this->getUserJobID([ + 'onDuplicate' => $onDuplicateAction, + 'mapper' => $mapper, + ])); $parser->init(); + $this->assertEquals($expectedResult, $parser->import($onDuplicateAction, $values), 'Return code from parser import was not as expected'); } + /** + * @param array $submittedValues + * + * @return array + * + * @throws \API_Exception + * @throws \CRM_Core_Exception + */ + protected function getUserJobID(array $submittedValues = []): array { + $userJobID = UserJob::create()->setValues([ + 'metadata' => [ + 'submitted_values' => array_merge([ + 'contactType' => CRM_Import_Parser::CONTACT_INDIVIDUAL, + 'contactSubType' => '', + 'dataSource' => 'CRM_Import_DataSource_SQL', + 'sqlQuery' => 'SELECT first_name FROM civicrm_contact', + 'onDuplicate' => CRM_Import_Parser::DUPLICATE_SKIP, + 'dedupe_rule_id' => NULL, + 'dateFormats' => CRM_Core_Form_Date::DATE_yyyy_mm_dd, + ], $submittedValues), + ], + 'status_id:name' => 'draft', + 'type_id:name' => 'contact_import', + ])->execute()->first()['id']; + if ($submittedValues['dataSource'] ?? NULL === 'CRM_Import_DataSource') { + $dataSource = new CRM_Import_DataSource_CSV($userJobID); + } + else { + $dataSource = new CRM_Import_DataSource_SQL($userJobID); + } + $dataSource->initialize(); + return $userJobID; + } + /** * Add a random extra option value * -- 2.25.1